I'm new to C++ and I normally use Java, so I have a hard time to get into pointers and references. I have to do a variation of binary search tree with inner nodes and leaf nodes (only leafs contain the data).
class Node
Node *parent;
Node *left;
Node *right;
//other stuff
}
I need to implement operator<< which adds a new node with value to the tree.
//adding a node to tree
void operator<<(int value){
if(size == 0){
//stuff
} else {
Node* temp = root;
getLeaf(temp,value);
//other magic
//temp will be used to append a new node into tree,
//so it has to point to the actual node in the tree
delete temp;
}
}
The point of function getLeaf is to find a leaf (may or may not contain the desired value) and store it into temp, which needs to be accessible in the operator<< function.
int getLeaf( Node* temp, int value) const{
int depth = 0;
//goes trough all inner nodes until it finds specific leaf
while(temp->isInner()){
++depth;
if(value < temp->getValue()){ //searched value is smaller
temp = temp->getLeft(); // to left subtree
continue;
} else {
temp = temp->getRight(); //to rightsubtree
continue;
}
return depth;
}
I am really confused how to do this and what is the right combination of pointers and values. If I set
Node* temp = root;
getLeaf(temp,value);
won't root get overridden while traversing the tree in getLeaf function?
Plus I need temp to point to actual node in the tree, so I can append a new node into it.
Could you please explain?
Migrating from Java to C++ is a bit tough. Migrating from C++ to Java is equally tough. To make things easy you just need to experiment.
In C++, pointers are variables that point to the location of another variable in memory and references are pointers that syntactically behave like the variable whose address is pointed to.
When arguments are passed to a function, the function does NOT receive the original arguments but a copy of them. The work you did is implement the traversal based on the above concepts. So how does it all "magically" work?
Your function: getLeaf(Node *&temp, int value) searches the correct leaf node and assigns it to temp at which insertion is to be performed. temp here is a copy of a reference to the pointer temp(in operator <<). So when the reference temp is assigned to in getLeaf, the pointer temp in operator << it points to is modified.
If I set
Node *temp = root;
getLeaf(temp,value);
won't root get overriden while traversing the tree in getLeaf function?
Note here that temp and root are two different pointers that point to the same variable. The content of the pointers is the same, they aren't and hence root is NOT overridden, when temp is updated.
But there is a problem later on in the code. If you delete temp;, root will also be deleted at the end of insertion as delete deletes the content pointed to by the pointer. Do NOT delete a pointer that is not allocated by a new.
Provide a separate function to free the dynamically allocated memory used by the tree, and call it at the end when you are done experimenting.
Related
Following is the code for searching an element in BST.
can anyone please explain what &(*cur)->right or &(*cur)->left means in the code?
Thank You
TreeNode *insertIntoBST(TreeNode *root, int val)
{
TreeNode **cur = &root;
while( *cur )
cur = (val > (*cur)->val) ? &(*cur)->right : &(*cur)->left;
*cur = new TreeNode(val);
return root;
}
cur is a pointer to pointer, thus, to access its children, you need to dereference it (*cur) and only then access the element (->left, ->right).
After you got the next element (right or left), which is a pointer, you need to store it in cur. But cur is a pointer to pointer, so you need to take a reference of if (using the & operator).
The overall expression is the ugly &(*cur).
By the way, the reason you need a pointer to pointer, is because of the line *cur = new TreeNode(val);.
If you would simply use a pointer, this line would do nothing, and only change your temporary pointer. Since you are using a pointer to pointer, you are changing the original node in the tree.
Those properties are right and left children of the current node. and the while traverses the tree to find the suitable place for the value as its bigger or less than current node as the Binary Search Tree definition
So I'm trying to write a function that places all of the values of a binary tree into a vector, which will later be used to recreate it. But when I try to call this function, I get an error:
Error in `./bst': double free or corruption (fasttop):
This is the function I'm using. The vector itself is a private variable containing nodes. size() returns the size of the tree and is working.
void BST::swapvector()
{
Node *ptr = m_root;
while (size() != 0)
{
if (ptr->m_left != NULL) {
ptr = ptr->m_left;
} else if (ptr->m_right != NULL) {
ptr = ptr->m_right;
} else {
Node *temp = ptr;
myvector.push_back(ptr); //starting from root, we traverse until we reach the bottom and then add ptr to the vector
ptr = m_root;
delete temp; //once we're finished, we delete temp
}
}
}
Does anyone know why this isn't working? Thanks!
It's obvious why this isn't working.
} else {
Node *temp = ptr;
myvector.push_back(ptr); //starting from root, we traverse until we reach the bottom and then add ptr to the vector
ptr = m_root;
delete temp; //once we're finished, we delete temp
}
You're storing a pointer to Node into vector and then deleting that Node with delete temp. After that pointer stored into vector points to garbage or non-existent memory.
"...a function that places all of the values of a binary tree into a vector..."
No, you're not storing binary tree values, you're storing pointers to binary tree values (Node objects).
There are two things you can do:
If the binary tree will not be freed nor changed for the lifetime of myvector then you can just remove the delete temp; line.
If assumption in the first case is not true, then you need to store Node elements into vector, not pointers to them. So, define myvector as vector<Node> myvector; instead of vector<Node *> myvector; and change myvector.push_back(ptr); to myvector.push_back(*ptr);.
You cannot delete temp after you place it a vector. Also, how is your vector defined? There might be problem there.
Also you should use iterators instead of push_back() function. It doesn't work well with pointers.
And, why does everyone insist on using c-style pointers. Use shared or unique pointers. Please?
Type of error usually signifies that a pointer being freed twice.
I feel really silly asking this, as it seems really simple, but I just can't figure it out. All I want to do is set the node pointer to the next node in the list. The function is from a teacher, I wrote the body, so I don't want to mess with the head of the function.
void LList::insert(int num, int at)
{
node* n = new node(num);
if (!n) throw runtime_error("Can't allocate node!");
if(!root || at == 0){
// if empty list - new node is root…
if (!root) root = n;
}
if(root){
node* nextNode = new node(num);
int numF = 0;
for (node* t = root; t != NULL ; t = t->next){
numF++;
if(numF == at){
n->next=t->next;
t->next=n;
}
}
}
}
Since it seems you are using n for the new node to be inserted into the linked list (I'm inferring that it's a singly linked list from the existing code and class name), there are a few things you have to do off the top of my head:
Identify the existing member of the list after which the new node will be inserted. You are making an attempt to do this already with that for loop, but in my opinion you may want to rewrite that as a while loop since you probably don't want it to keep iterating after the insertion position has been identified. Alternately, you could short-circuit out of the for loop with a break once you've found the right place for insertion, but I don't like that for stylistic reasons. :)
Set the newly inserted node's next pointer to the same location to which the next pointer of the node identified in #1.
Set the next pointer of the node identified in #1 to point at the new node, thus re-establishing the integrity of the chain.
Your code looks like it is attempting to do #2 and #3 out of order, which won't work. You're obliterating the value of t->next before you've had a chance to point n->next at it.
Finally, you may need to define some behavior to which you can fall back in case you are adding to a position not already defined in the list (i.e. inserting into the fourth position of a linked list that currently has three elements). You may need to re-jigger your loop to terminate when t->next is null rather than when t itself is null - otherwise you lose the hook to be able to connect the (currently) last element of the list to your new node.
I am trying to write some data structure HW in C++. When I was trying to construct a binary tree using a queue, I was somehow confused by the pointer issues.
class Tree{
private:
struct TreeNode{
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) :val(x), left(NULL), right(NULL) {}
};
public:
TreeNode* root = NULL;
Tree();
Tree(queue<int>& val);
~Tree();
string toString_bf();
};
Tree(queue<int> &vals){
if (vals.empty())
return;
root = new TreeNode(vals.front());
vals.pop();
queue<TreeNode**> pts; // what is the meaning of this? Why should use pointers to pointer?
pts.push(&(root->left)); // also have doubts here, about the reference used in the parameter
pts.push(&(root->right));
while (!vals.empty()){
TreeNode* t = new TreeNode(vals.front());
*(pts.front()) = t; // and here
pts.pop();
vals.pop();
pts.push(&(t->left));
pts.push(&(t->right));
}
}
According to my understanding, left and right are both pointers, why could not just pass values to them?
The variable pts is a queue of pointers to where subtrees need to be placed later. Those locations are themselves pointers to TreeNode (each being either a left or right data member, of type TreeNode *) so it makes sense that you need a TreeNode ** to point at them.
In other words, each time *(pts.front()) = t; is executed, a left or right member of a previously contructed TreeNode is being set to point to the most recently constructed node.
You could make a typedef TreeNode *TreePtr; and perhaps it would look cleaner using that.
To further clarify what's happening:
Each time the 'while' loop starts:
root is the root of a tree under construction, containing n+1 nodes, each holding one value taken from the input queue vals (where n is the number of times the while loop has already run)
vals contains all the remaining values yet to be put into the tree (if any)
pts contains a set of pointers to pointers within the nodes in the tree; it contains pointers to all of the pointers which have not yet had subtrees assigned to them; there are n+2 of these.
So each loop makes one new node, makes one of these unassigned pointers point at the new node, and then adds the new node's unassigned pointers to the queue.
Note that when the operation ends, there are always n+2 pointers in pts, which are discarded. By knowing how many nodes are needed ( = vals.size()) it's possible to stop doing the pts.push operations once enough have been done, which reduces the amount of temporary space needed by about 50%:
vals.pop();
if( pts.size() < vals.size()) {
pts.push(&(t->left));
pts.push(&(t->right))
} // otherwise we have enough for all remaining vals.
It is difficult to understand how this node is being created, Can you please write step-wise what this set of code is actually doing, and what actions they represent?
void list::create_node(int value)
{
struct node *temp;// Please write in words the meaning of this statement
temp = new(struct node);// is this a dynamic node? )
temp->info = value;// is this value being assigned to this node?
if (last == NULL)// what is this set of code testing??
{
last = temp;// who is this last; the node which has been created?
temp->next = last; // is the node pointing to itself being only one node?
}
else
{
temp->next = last->next;((( // What is this statement saying?
last->next = temp;// What is this statement saying?
last = temp;// What is this statement saying?
}
}
void list::create_node(int value)
{
The above line declares a function that creates a node with the given value and inserts the node into the list. The code must be examined to see where the new node is inserted.
struct node *temp;
Declares a pointer to a node. The memory has not been allocated yet, only a pointer that will be used later.
temp = new(struct node);
Allocates memory for a node from the dynamic (runtime) memory area (a.k.a. heap). Calls the constructor of the node structure to initialize the memory, if a constructor exists.
The pointer temp is now pointing to the node object.
temp->info = value;
This assigns the value to the data field, info. Need the declaration of struct node in order to confirm this guess.
if (last == NULL)
{
Assuming that last is a pointer and points to the last node, this check is looking for an empty list. Common implementation is to have pointer values set to null to mark the end of the list.
last = temp;
temp->next = last;
}
The above code inserts the new node as the last node. The last pointer allows fast access to the end of the list. This allows for reverse iteration without having to traverse all the links to find the last node.
Some implementations set the next field to null to indicate the end of the list, others like this one, make it point to the last node.
else
{
temp->next = last->next;
At this point, the list is not empty.
The new node is made to point to the same node that the last node points to.
This is best understood by drawing the node boxes and arrows pointing to the nodes.
last->next = temp;
Updating the last node to point to itself. See the above section.
last = temp;
Updating the pointer to the last (end of list) node to point to the new node.
}
}
I suggest you draw the linked list and walk through this algorithm a couple of times to see how it works. Also review the singly linked list data type.
The circular reference of the last node may be confusing to you. This may not be the standard implementation that most books describe, but it is valid.