I am seeking a way to recursively maintain the parent pointer in my AVL tree insert.
I am aware that this is not the usual process however I am meant to have a function to manually rotate the nodes so the parent is necessary.
The closest I've gotten is to maintain the parents of the root and the nodes that are not pointing to NULL. all the others will just point to themselves. If I uncomment my other parent insertion, I get segfaults.
AVL::node *AVL::insert(int k, string d, node *&n)
{
//recursive base case, I imagine n->parent = n should not be here
if (n == NULL) {
n = new node;
n->left = NULL;
n->right = NULL;
n->key = k;
n->data = d;
n->height = 1;
n->parent = n;
return n;
}
if (n->key > k) {
if (n->left != NULL) {
n->left->parent = n;
insert(k, d, n->left);
} else {
//n->left->parent = n;
// this creates SEGFAULT
insert(k, d, n->left);
}
} else if (n->key < k) {
if (n->right != NULL) {
n->right->parent = n;
insert(k, d, n->right);
} else {
//n->right->parent = n;
// this creates SEGFAULT
insert(k, d, n->right);
}
} else {
return n;
}
// insert height management here
updateHeight(n);
return n;
}
You almost got it. The remaining piece of the puzzle you missed is:
insert(k, d, n->left);
Your approach of passing in a reference to what would become the pointer that's would be pointing to the newly created node in your AVL tree (in this case this would be n->left), is the right approach.
Your missing piece is making the obvious observation that the new node needs to know it's parent, and you're staring at it, right here, on the above line. It's n:
insert(k, d, n, n->left);
Now, insert() knows the parent node (and the other recursive call, that uses n->right, does the same thing):
AVL::node *AVL::insert(int k, string d, node *parent, node *&n)
You can completely broom away all that convoluted logic that attempts to fiddle with parent, and whether the pointers were nullptr before/after the recursive calls. Your recursive insert() knows exactly what the parent is, in a much simpler fashion:
if (n == NULL) {
n = new node;
n->left = NULL;
n->right = NULL;
n->parent = parent;
That's pretty much it, this becomes a big, fat, nothingburger. Presumably, the initial call to insert(), that start rolling the ball down the hill with the AVL tree's root node will pass a nullptr for the parent parameter, and everything works out by itself.
Okay so I seem to have gotten a bit lost. I am trying to insert data into a tree and when checking for balance and whether or not to rotate, I default to checking through the root. When I check examples online, I see that we can also rotate along other nodes in the tree as well. How do we figure out which node to use to balance the tree and how do we reach said node? I also saw that instead of having void functions to implement the insert and rotation functions, people use a node pointer return type instead. What is the purpose of that? I know the answers may be super obvious I am just lost.
struct TNode{
int data;
TNode* left;
TNode* right;
};
class Tree{
public:
TNode* root;
public:
Tree()
{root = nullptr;}
int height(TNode* node);
int balanceFactor(TNode* node);
bool isBalance(TNode* node)
{return balanceFactor(node)<-1 && balanceFactor(node)>1?true:false;}
void avlInsert(int key);
void LLRotation(TNode* node);
};
int Tree::height(TNode* node){
int l = 0;
int r = 0;
if(!node->left && !node->right)
return 0;
if(node->left)
l = height(node->left) + 1;
if(node->right)
r = height(node->right) + 1;
return l > r ? l : r;
}
int Tree::balanceFactor(TNode *node){
if(node->left && node->right)
return height(node->left) - height(node->right);
else if(node->left && !node->right)
return height(node);
else
return -1 * height(node);
}
void Tree::LLRotation(TNode *node){
TNode* nl = node->left;
node->left = nl->right;
nl->right = node;
if(root == node)
root = nl;
}
void Tree::avlInsert(int key){
TNode* trav;
TNode* follow;
TNode* node = new TNode;
node->data = key;
node->left = nullptr;
node->right = nullptr;
if (!root)
root = node;
else{
trav = root;
while (trav){
if (key < trav->data){
follow = trav;
trav = trav->left;
}
else{
follow = trav;
trav = trav->right;
}
}
if(key < follow->data)
follow->left = node;
else
follow->right = node;
}
if (balanceFactor(root) == 2 && balanceFactor(root->left) == 1)
LLRotation(root);
}
It really depends on your implementation some people they want to return a node, using a void function does not change the result much. For insert function you need to check only after you insert the node so you can go ahead and insert that node than rotate it. Please note that this function will only work if you have an AVL Tree to start with. Also your code is not correct, below:
if (balanceFactor(root) == 2 && balanceFactor(root->left) == 1)
LLRotation(root);
This is not how you check it for insertion.... That's for deletion buddy, I think you are getting mixed up. Usually for insertion you check if the balanceFactor is between 1 and -1, so if you are getting 2, then it is a left heavy tree, in your case, because it is left-right, which means you should do Right rotation........ Buddy......
int l = 0;
int r = 0;
if(!node->left && !node->right)
return 0;
if(node->left)
l = height(node->left) + 1;
if(node->right)
r = height(node->right) + 1;
return l > r ? l : r;
Height function, extremely inefficient... Instead define height as a variable for node and then modify it after each insertion, deletion.
I am struggling to understand why the function CountNodes() below counts all the nodes in a BST.
If we assume we have the following BST:
20
/ \
10 30
/ \ / \
5 15 25 35
If I call CountNodes(pointer to root node 20); then wouldn't the relevant if statement:
if(root->left!=NULL)
{
n=n+1;
n=CountNodes(root->left);
}
simply look at node 10 and say, yes it is not null, add 1 to the counter n, and then call CountNodes(pointer to 10) which would then just send us down the left branch again to 5. Then when at 5 the left and right variables are NULL and hence the whole CountNodes function just returns n equal to int 3.
I guess I am struggling to understand exactly when the value of the argument to CountNodes is updated. Do we look right and check if its NULL and update the counter before we update the argument value in the first recursive call to CountNodes(pointer to 10) in the left look even though the right look appears after the left recursive call in the code?
#include<iostream>
using namespace std;
int n=1;
struct node
{
int data;
node* left;
node* right;
};
struct node* getNode(int data)
{
node* newNode=new node();
newNode->data=data;
newNode->left=NULL;
newNode->right=NULL;
return newNode;
}
struct node* Insert(struct node* root, int data)
{
if (root == NULL)
return getNode(data);
if (data < root->data)
root->left = Insert(root->left, data);
else if (data > root->data)
root->right = Insert(root->right, data);
return root;
}
int CountNodes(node*root)
{
if(root==NULL)
return 0;
if(root->left!=NULL)
{
n=n+1;
n=CountNodes(root->left);
}
if(root->right!=NULL)
{
n=n+1;
n=CountNodes(root->right);
}
return n;
}
int main()
{
node* root=NULL;
root=Insert(root,10);
Insert(root,5);
Insert(root,20);
Insert(root,4);
Insert(root,8);
Insert(root,15);
Insert(root,25);
cout<<"Total No. of Nodes in the BST = "<<CountNodes(root)<<endl;
return 0;
}
You are overwritting the value of n
n=CountNodes(root->left);
You should be adding the count from the sub tree.
n = n + CountNodes(root->left);
There is also another bug in that you are counting this node twice if the node has a left and right tree and never counting it if the node has no subtrees.
if(root->left!=NULL)
{
n=n+1; // Adding one for this node.
n=CountNodes(root->left);
}
if(root->right!=NULL)
{
n=n+1; // Adding one for this node again?
n=CountNodes(root->right);
}
I think you should be doing:
if(root->left!=NULL)
{
n = n + CountNodes(root->left);
}
if(root->right!=NULL)
{
n = n + CountNodes(root->right);
}
n = n + 1;
The next thing is that you check for null on entry into the function. So you don't need to test for null before doing a recursive call.
n = n + CountNodes(root->left);
n = n + CountNodes(root->right);
n = n + 1;
We can then simplify this to:
int CountNodes(node* root)
{
if (root == nullptr) {
return 0;
}
return 1 + CountNodes(root->left) + CountNodes(root->right);
}
I have written a node insertion code for a BST. But it dosen't seem to work correctly. Its giving a "Segmentation error". Here is my logic for insertion.
void insert(Node* root, int data){
if(root==NULL){
root= new Node;
root->data = data;
}
else if(data < root->data){
insert(root->left,data);
}
else if(data> root->data){
insert(root->right,data);
}
}
How do i fix it? Thanks
Edit: so i tried out some things and this one does the trick
Node* insert(Node* &root, int data){
if(root==nullptr){
root = create(data);
return root;
}
else if(data < root->data){
insert(root->left,data);
}
else if(data> root->data){
insert(root->right,data);
}
}
Whats the difference between Node* root and Node* &root ?
Well, if node doesn't exists (it's NULL), you're just setting your root pointer to new Node, but you're missing to 'hang it up' to it's parent. And as already mentioned, you can use unique_ptr-s since C++11 to avoid memory leaks (that's when you forget to delete object). It looks like:
struct Node {
int data = -1; // not initialized
std::unique_ptr<Node> l;
std::unique_ptr<Node> r;
}
void insert(Node *root, int data) {
if (root->data == -1) {
root->data = data;
return;
}
if (data < root->data) {
if (!root->l) {
// hanging new left node up
root->l = std::make_unique<Node>(); // std::make_unique comes since C++14
}
insert(root->l.get(), // getting raw ptr
data);
}
else {
if (!root->r) {
// hanging new right node up
root->r = std::make_unique<Node>();
}
insert(root->r.get(), data);
}
}
Also you might be interested in data structure called treap, because your implementation may work very long if you insert, for example, increasing sequence:
Node root;
for (int i = 1; i <= 100'000; i++) {
insert(&root, i);
}
So your binary tree in this case looks like:
1
\
2 <=
\ <= very long path
3 <=
\
...
\
100'000
Treap helps to avoid long paths in your BST.
Given a binary search tree, i need to convert it into a doubly linked list(by traversing in zig zag order) using only pointers to structures in C++ as follows,
Given Tree:
1
|
+-------+---------+
| |
2 3
| |
+----+---+ +----+---+
| | | |
4 5 6 7
| | | |
+--+--+ +--+--+ +--+--+ +--+--+
| | | | | | | |
8 9 10 11 12 13 14 15
Node Structure:
struct node
{
char * data;
node * left;
node * right;
};
Create List(zig zag order):
1 <-> 3 <-> 2 <-> 4 <-> 5 <-> 6 <-> 7 <-> 15 <-> ... <-> 8
Could someone please help me out.
This is a Breadth-first search algorithm. Wikipedia has a good explanation on how to implement it.
After implementing the algorithm, creating your linked list should be a no-brainer (since it will only be a matter of appending each visited element to the list)
That's an awkward type of tree traversal. I wonder how often anyone has ever actually needed to do such a thing in real code. Nevertheless, it's the problem to be solved here...
Here's how I would approach dealing with this:
First, when I compare the desired output to the structure of the tree, I notice that each "level" of the tree is processed in turn from top to bottom. So top node first, then all child nodes, then all grand-child notes, and so on. So probably a good solution will involve a loop that processes one level and at the same time builds up a list of nodes in the next level to be used in the next iteration of the loop.
Next, this "zig zag" order means it needs to alternate which direction the child nodes are processed in. If a particular iteration goes from left to right, then the next iteration must go from right to left. And then back to left to right for the subsequent iteration and so on. So in my idea of a loop that processes one level and builds a list of the next level, it probably needs to have some sort of alternating behavior when it builds that list of nodes for the next level. On even iterations the list is built one way. On odd iterations the list is built the other way.
Alternatively, another other way to think about this whole thing is: Design a solution to that can build the result list in 1,2,3,4,5,6,etc order. Then modify that design to have the zig zag order.
Does this give you enough of an idea on how to design a solution?
This might help you:
Create a separate list for every level of the tree
Traverse the tree and copy the values to the lists as you traverse the tree
Reverse the order of every other list
Connect the lists
In this solution below I have used two stacks to store Levels alternatively.
say nodes at level 0 will be store in stack 1 whose name is head1;now pop the element while it not become empty and push the elements in stack 2.the order i.e left or right child of insertion will depend on the level.and change the insertion order at each level.
node * convert_to_dll(node *p)
{
static int level=0;
push_in_stack(p,&head1);
printf("%d\n",p->data);
while( head1!=NULL || head2!=NULL) {
//pop_from_queue(&headq);
if(head1!=NULL && head2==NULL) {
while(head1!=NULL) {
if(level%2==0) {
node *p;
p=new node;
p=pop_from_stack(&head1);
if(p->right!=NULL) {
push_in_stack(p->right,&head2);
printf("%d\n",(p->right)->data);
}
if(p->left!=NULL)
{
push_in_stack(p->left,&head2);
printf("%d\n",(p->left)->data);
}
}
}
//traverse_stack(head2);
level++;
} else {
while(head2!=NULL) {
if(level%2!=0) {
node *q;
q=new node;
q=pop_from_stack(&head2);
if(q->left!=NULL) {
push_in_stack(q->left,&head1);
printf("%d\n",(q->left)->data);
}
if(q->right!=NULL) {
push_in_stack(q->right,&head1);
printf("%d\n",(q->right)->data);
}
}
} //traverse_stack(head2);
level++;
}
}
return p;
}
you can write a function to add nodes in a doubly linked list. You can then call this function while traversing the tree. In this way you should be able to do it.
Hmm... This is a tough one. The problem with traversal in this order is that you are doing a lot of skipping around. This is generally true in any tree traversal order that is not depth or breadth first.
Here's how I would resolve the situation. Start with a single, empty array of lists of nodes and begin traversing the tree depth first. Be sure to keep track of the depth of your traversal.
At each point in traversal, note the depth of your traversal and pick the list at the index in the array. If there isn't one there, add it first. If the depth is even (Assuming root has depth 0), add the node to the end of the list. If it's odd, add it to the beginning.
Once you've traversed all nodes, concatenate the lists.
Why use pointers?? You could just store your BST as an array A[1...n]. So, A[1] would have root, A[2] and A[3] would have nodes of the depth 1, etc. This is possible since it is an almost complete tree, and you know how many elements will be present at a given depth - i.e. 2^d at depth d (except of course at the last depth). Now all you've got to do is access the array in a zag-zag manner, and create a new BST (array) of the new order. So, how would you traverse the array in a zig-zag manner?? For any given element A[i], the left child would be A[2i] and the right child A[2i + 1]. So, if your current depth d is odd, then traverse 2^d elements, and when you reach the 2^dth element, go to its left child. If your current depth d is even, again traverse 2^d elements, but when you reach the 2^dth element, go to its right child. Storing them as arrays rather than nodes makes your data structure leaner, and your implementation simpler.
This ( http://cslibrary.stanford.edu/109/TreeListRecursion.html) has the answer with pretty pictures :)
#include<iostream>
#include<conio.h>
using namespace std;
class TreeNode
{
public:
int info;
TreeNode* right;
TreeNode* left;
//TreeNode* parent;
TreeNode()
{
info = 0;
right = left = NULL;
}
TreeNode(int info)
{
this -> info = info;
right = left = NULL;
}
};
class ListNode
{
public:
int info;
ListNode* next;
ListNode()
{
info = 0;
next = NULL;
}
ListNode(int info)
{
this -> info = info;
next = NULL;
}
};
TreeNode* root = NULL;
ListNode* start;
ListNode* end;
void addTreeNode(TreeNode*);
void convertTreeToList(TreeNode*);
void printList(ListNode*);
int findDepth(TreeNode*);
int _tmain(int argc, _TCHAR* argv[])
{
start = end = new ListNode(0);
char choice = 'y';
int info;
while(choice == 'y')
{
cout<<"Enter the info of new node:\n";
cin>>info;
addTreeNode(new TreeNode(info));
cout<<"Want to add a new node to the tree?(y/n)\n";
cin>>choice;
}
cout<<"Depth of the tree is: "<<findDepth(root);
cout<<"Converting the tree into a doubly linked list....\n";
convertTreeToList(root);
printList(start->next);
cin>>choice;
return 0;
}
void addTreeNode(TreeNode* node)
{
if(!root)
{
root = node;
}
else
{
TreeNode* currRoot = root;
while(1)
{
if(node -> info >= currRoot -> info)
{
if(!currRoot -> right)
{
currRoot -> right = node;
break;
}
else
{
currRoot = currRoot -> right;
}
}
else
{
if(!currRoot -> left)
{
currRoot -> left = node;
break;
}
else
{
currRoot = currRoot -> left;
}
}
}
}
}
void convertTreeToList(TreeNode* node)
{
if(node -> left != NULL)
{
convertTreeToList(node -> left);
}
end ->next = new ListNode(node -> info);
end = end -> next;
end -> next = start;
if(node -> right != NULL)
{
convertTreeToList(node -> right);
}
}
void printList(ListNode* start)
{
while(start != ::start)
{
cout<<start->info<<" -> ";
start = start -> next;
}
cout<<"x";
}
int findDepth(TreeNode* node)
{
if(!node)
{
return 0;
}
else
{
return (max(findDepth(node -> left), findDepth(node -> right)) + 1);
}
}
Linked list you get here is singly linked and sorted. Hope you can easily make changes in this code to get a doubly linked list. Just copy - paste this code and compile it.It will work fine.
Let us assume that the root of the binary tree is at level 0(an even number). Successive levels can be considered as alternating between odd even (children of root are at odd level, their children are at even level etc.). For a node at even level, we push its children onto a stack(This enables reverse traversal). For a node at odd level, we push its children onto a queue(This enables forward traversal). After children have been pushed, we remove the next available element (top of stack or front of queue) and recursively call the function by changing level to odd or even depending on where the removed element lies. The removed element can be inserted at the end of the doubly linked list. Pseudo-code below.
// S = stack [accessible globally]
// Q = queue [accessible globally]
//
// No error checking for some corner cases to retain clarity of original idea
void LinkNodes(Tree *T,bool isEven,list** l)
{
if(isEven) {
S.push(T->right);
S.push(T->left);
while( !S.empty() ) {
t = S.pop();
InsertIntoLinkedList(l,t);
LinkNodes(t,!isEven);
}
} else {
Q.enque(T->left);
Q.enque(T->right);
while( !Q.empty() ) {
t = Q.deque();
InsertIntoLinkedList(l,t);
LinkNodes(t,isEven);
}
}
}
In the calling function:
bool isEven = true;
list *l = NULL;
// Before the function is called, list is initialized with root element
InsertIntoLinkedList(&l,T);
LinkNodes(T,isEven,&l);
/* * File: main.cpp * Author: viswesn * * Created on December 1, 2010, 4:01 PM */
struct node {
int item;
struct node *left;
struct node *right;
struct node *next;
struct node *prev;
};
struct node *dlist = NULL;
struct node *R = NULL;
struct node* EQueue[10] = {'\0'};
int Etop = 0;
struct node* OQueue[10] = {'\0'};
int Otop = 0;
int level=-1;
struct node *insert(struct node *R, int item)
{
struct node *temp = NULL;
if (R != NULL) {
if (item < R->item) {
R->left = insert(R->left, item);
} else {
R->right = insert(R->right, item);
}
} else {
temp = (struct node *)malloc(sizeof(struct node));
if (temp == NULL) {
return NULL;
}
temp->item = item;
temp->left = NULL;
temp->right = NULL;
temp->next = NULL;
temp->prev = NULL;
R = temp;
}
return R;
}
void print(struct node *node)
{
if (node != NULL) {
print(node->left);
printf("%d<->", node->item);
print(node->right);
}
}
void EvenEnqueue(struct node *item) {
if (Etop > 10) {
printf("Issue in EvenEnqueue\n");
return;
}
EQueue[Etop] = item;
Etop++;
}
void OddEnqueue(struct node *item)
{
if (Otop > 10){
printf("Issue in OddEnqueue\n");
return;
}
OQueue[Otop] = item;
Otop++;
}
int isEvenQueueEmpty() {
if (EQueue[0] == '\0') {
return 1;
}
return 0;
}
int isOddQueueEmpty()
{
if (OQueue[0] == '\0') {
return 1;
}
return 0;
}
void EvenDQueue()
{
int i = 0;
for(i=0; i< Etop; i++)
EQueue[i]='\0';
Etop = 0;
}
void OddDQueue()
{
int i = 0;
for(i=0; i< Otop; i++)
OQueue[i]='\0';
Otop = 0;
}
void addList() {
int counter = 0;
struct node *item = NULL;
if (level%2 == 0) {
/* Its Even level*/
while(counter < Etop)
{
struct node *t1 = EQueue[counter];
struct node *t2 = EQueue[counter+1];
if ((t1!=NULL) && (t2!=NULL)) {
t1->next = t2;
t2->prev = t1;
}
counter++;
}
item = EQueue[0];
} else {
/* Its odd level */
while(counter < Otop)
{
struct node *t1 = OQueue[counter];
struct node *t2 = OQueue[counter+1];
if ((t1!=NULL) && (t2!=NULL)) {
t2->next = t1;
t1->prev = t2;
}
counter++;
}
item = OQueue[Otop-1];
}
if(dlist !=NULL) {
dlist->next = item;
}
item->prev = dlist;
if (level%2 == 0) {
dlist = EQueue[Etop-1];
} else {
dlist = OQueue[0];
}
}
void printTree()
{
int nodeCount = 0;
int counter = 0;
if (!isEvenQueueEmpty()) {
/* If even level queue is not empty */
level++;
nodeCount = pow(2,level);
printf("[");
while(counter < nodeCount) {
if (EQueue[counter] != '\0') {
struct node *t = EQueue[counter];
printf("%d<->", t->item);
if (t->left != NULL)
OddEnqueue(t->left);
if (t->right != NULL)
OddEnqueue(t->right);
} else {
break;
}
counter++;
}
addList();
printf("]");
EvenDQueue();
}
counter = 0;
if (!isOddQueueEmpty()){
/* If odd level queue is not empty */
level++;
nodeCount = pow(2,level);
printf("[");
while(counter < nodeCount){
if (OQueue[counter] != '\0') {
struct node *t = OQueue[counter];
printf("%d<->", t->item);
if (t->left != NULL)
EvenEnqueue(t->left);
if (t->right != NULL)
EvenEnqueue(t->right);
} else {
break;
}
counter++;
}
addList();
printf("]");
OddDQueue();
}
if (isEvenQueueEmpty() && isOddQueueEmpty()){
return;
}
else {
printTree();
}
}
void printLevel(struct node *node)
{
if (node == NULL)
return;
EvenEnqueue(node);
printTree();
printf("\n");
}
void printList(struct node *item)
{
while(item!=NULL) {
printf("%d->", item->item);
item = item->next;
}
}
int main(int argc, char** argv) {
int a[]={20,30,40,12,2,15,18};
int size = sizeof(a)/sizeof(int);
int i = 0;
for(i=0; i< size; i++) {
R = insert(R, a[i]);
}
printf("Inoder traversal - Binary tree\n");
print(R);
printf("\n\n");
printf("Level traversal - Binary tree\n");
printLevel(R);
printf("\n");
printf("Double link list traversal - Binary tree\n");
printList(R);
printf("\n");
return 0;
}