Constructing a binary tree using queue in C++ - c++

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.

Related

Understanding pointers in binary tree

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.

Member function returns the previous value of a variable

I am constructing an AVL tree program. I got stuck in a rather easy situation, but difficult to understand what is wrong. The reason I think it is the program's fault and not mine is because I have the exact same class function right before it with "left" and "right" swapped and it works just fine...
As you can see, the function returns the temproot pointer which is equal to temp2 if root==temp. The funny thing is, that although when I test-print the value of temproot JUST before it returns it (that in my example is 15), the actual value that is returned is STILL 20 (the previous value of temproot). I triple checked everything. It doesn't seem to return the newly acquired value... What may be the problem?
To be more specific, the exact code is this:
//structure
struct avlnode
{
int data;
avlnode * left;
avlnode * right;
}* root;
//class function
avlnode * Tree::RL_rotation (avlnode * temp)
{
avlnode * temproot = temp;
avlnode * temp1= new avlnode;
temp1=temp->right;
avlnode * temp2= new avlnode;
temp2=temp1->left;
temp1->left=temp2->right;
temp2->right=temp1;
temp->right=temp2;
temp->right=temp2->left;
temp2->left=temp;
if (root==temp)
{
root=temp2;
temproot=temp2;
}
cout << "temproot= " << temproot->data << endl;
return temproot;
}
I don't see a problem in the functionality you are seeing.
Pointers work in different ways than your typical objects (values), and are pretty hard to explain without having drawing board at hand, but let me try.
When you "remember" the pointer to initially passed in node, you are remembering just that. Even if you assign initial pointer to different structure fields, "move it around", your "copy" will still point at the exact same element, since the actual memory doesn't move when you are assigning/reassigning pointers. And, because of that (in your case), the rotation you are doing, won't be reflected by the parent element, of the initially passed in root, since it would still be pointing to the same element that got assigned to temp2->left (as is temproot, since the actual memory weren't reassigned).
If you want to change (have access to) the location where the actual element is stored. As I assume is within your case, you need to pass in the root element of the rotation by reference (avlnode* Tree::RL_rotation (avlnode*& temp)). And by doing that, you will pass, to the function, not only the memory location of your node, around which you want to do the rotation, but the location of the location as well. Which would allow to change the root, after the rotation, which you weren't able to do before.
Note: Get rid of code like this:
avlnode * temp1= new avlnode;
temp1=temp->right;
You are creating a new memory location, which you immediately forget, and it never gets released (there's no garbage collector in native C++).
Instead, write like this (since you don't really need to create new node - you are only rearranging them):
avlnode * temp1= temp->right;

Accessing Vector of Nodes

Just a quick C++ question. I've been trying to save a node inside a vector to the right child of a node.
For example,
I have a struct called node that has a pointer leading to a left child and a right child.
So:
struct node{
node *left;
node *right;
};
My vector of nodes,
vector<node> nodeVec;
consists of nodes as well.
The goal is to then take a node out of my vector and save as the right and left child of a new node.
So:
node *tree = new node();
tree->left = *nodeVec.at(0);
tree->right = *nodeVec.at(1);
But it throws an error saying that it doesn't recognize the '*' operator. Trying just
tree->left = nodeVec.at(0)
It says that I can't convert a node to a node*.
But if I use,
tree->left = &nodeVec.at(0)
It succesfully saves the address inside my left child.
I took a look at a couple of sites and answers and I think the one found here,
Dereference vector pointer to access element,
might've been the most relevant. I gave it a shot and threw so many errors, I didn't quite understand.
In short, from what i've read, I need to dereference the node inside my vector. But if it doesn't accept the '*' operator, how would one do that?
Thanks in advance!
You can access nodes in the vector like this:
node* p_left = nodeDev.at(0).left;
node copy_constructed_node(*(nodeDev.at(0).right));
You can also use your tree:
node* p_left = tree->left; // your code set this to &nodeVec[0]
More generally, I suggest you do some background reading on pointers (maybe here), or - better yet - consider whether a Standard container will satisfy your needs - e.g. std::map (tutorial here).

linked list first member variable of node structure always next node

Suppose you have a linked list of nodes as defined below:
C++ code
struct node {
node *next;
int i ;
};
Is there any benefit in making the next pointer as the first member variable of the structure ?
I think that people try this via the above approach (I may be wrong here)
node n, m;
*n=&m;
If above is right, is it right to code like above. What's the right way?
Is there any benefit in making the next pointer as the first member
variable of the structure ?
A very small performance benefit can be reached to reduce the assembly instruction size in loads from and writes to zero offset members, but only in classes without virtual table (vtbl is a omitted first member).
If you want prebuild a scope/global allocated list, its elements can be initialized as mentioned.
You can try it:
struct node {
struct node* next;
int i;
};
node z = {0}, c={&z}, b={&c}, a={&b};
node * stack = &a;
you can find very useful information about liked list searching for 'linux kernel linked list':
Linux Kernel Linked List Explained
How does the kernel implements Linked Lists?
I working now in my own design of 'intrusive node' general purpose containers using c++ templates, perhaps this question might seem interesting.
node n, m;
*n = &m;
is not legal code, perhaps you mean
node n, m;
n.next = &m;
but normally this would be done with dynamic allocation
node* n = new node;
n->next = new node;
because normally you would use node to create a variable length list. Since the length of the list varies there is no way to declare the right number of variables, instead you must allocate the nodes dynamcally.

Finding last element in linked structure heap

I was wondering how you would go about finding the furthest element in a linked structure implementation of a heap and the root element. I want to be able to Enque and Deque elements.
Some clarification:
what I meant was lets say you have a linked structure making up a max heap (root element has the largest value). Your tree would have an element somewhere at the very bottom which you would insert after or remove depending on if you are enqueing or dequeing. How do you determine that element? and how do you determine the root node of the tree? (the top one)
I'm not completely positive this is what you are asking for, but this is one way of pointing to the last element of a singly-linked list:
T *p = NULL, *q = NULL; // q follows p by one node
p = root;
while (p)
{
q = p;
p = p -> next;
}
// q now points to last node
The normal method for adding something to a heap structure is to start at the root and "walk" the tree to find the place where the new element goes. When you find where it goes, you put it there, and if that means replacing what's already in that spot, then you take the previous value and keep walking down to find where it goes. Repeat until you hit a leaf, then add whatever value you're "carrying" as the appropriate child of that leaf.
Suppose your new value was 5 and the root node of the heap held a 10. 5 clearly goes below 10, so you look at the children of 10. Suppose they're 8 and 7. Both are larger than 5, so pick one (how you pick one depends on whether you're trying to keep the heap balanced). Suppose you pick 7, and it has children 3 and 4. 5 goes below 7 but above 3 or 4, so you replace, say, the 4 with 5, then look at that node's children to see where to put the 4. Suppose it has no children, you can just add a new leaf containing 4.
As for your question about how you find the root -- generally the root is the only pointer to the tree that you keep. It's your starting point for all operations. If you started somewhere else, I suppose you could navigate up to the root, but I'd question why.
Maybe something like this ?
struct node {
node *parent;
node *children[2];
int data; //or whatever else you want
};
struct heap {
node *root;
node *last;
};
This is a lot trickier to implement then just using an array though. Here is a hypothetical add
void add(struct heap* h, int d)
{
node* add = malloc(sizeof(node));
add->data = d;
node* current = h->root;
while(current->children[1]) current = current->children[1];
current->children[1] = add;
add.parent = current;
add.children[0] = NULL;
add.children[1] = NULL;
h.last = add;
percolate_up(h);
}
Something like that.