Where does MQL4 / MQL5 implementation of originally C++ AVL Tree Parent node exhibit an issue? - avl-tree

I dont know where I am having an issue, but I am getting a strange error in my AVL implementation, translated into MQL4/MQL5 language.
In failed case, I am getting into either
recursively pointing to same node problem
or
a detached node without any parent,
thus while balancing, I am running into null pointer issue.
Test Cases:
A copy / paste of the MetaTrader4/5 Terminal [ Journal ] is enclosed below
Pass Case:
AVLTree *theAVLTree;
// Create a tree and test case 2
theAVLTree = new AVLTree();
Print("-----------------------------------------------");
Print("TESTING CASE 2");
// Add 50
Print("Adding Node 50");
theAVLTree.Insert(theAVLTree.CreateNewNode(50,4));
theAVLTree.PrintTree();
// Add 20
Print("Adding Node 20. Ancester's balance factor changes to L");
theAVLTree.Insert(theAVLTree.CreateNewNode(20,5));
theAVLTree.PrintTree();
// Add 70
Print("Adding Node 70 to trigger test of Case 2. Ancester's balance factor changes to =");
theAVLTree.Insert(theAVLTree.CreateNewNode(70,6));
theAVLTree.PrintTree();
// Add 90
Print("Adding Node 90. Ancester's balance factor changes to R.");
theAVLTree.Insert(theAVLTree.CreateNewNode(90,7));
theAVLTree.PrintTree();
// Add 15
Print("Adding Node 15 to trigger test of Case 2. Ancesters balance factor changes to =");
theAVLTree.Insert(theAVLTree.CreateNewNode(15,8));
theAVLTree.PrintTree();
Print("END TESTING CASE 2");
delete theAVLTree;
Print("-----------------------------------------------");
Print("-----------------------------------------------");
Failed Case:
AVLTree *theAVLTree;
//;;;;1.29397;1.29316;1.29259;1.29226;1.29298
// Test each case by adding some nodes to the tree then
// printing the tree after each insertion
// Create a tree and test case 1
theAVLTree = new AVLTree();
Print("TESTING CASE 1");
// Add 50
Print("Adding Node 1.29567");
theAVLTree.Insert(theAVLTree.CreateNewNode(1.29567,0));
theAVLTree.PrintTree();
// Add 20
Print("Adding Node 1.29431 to trigger test of Case 1 to left. Root is ancester.");
theAVLTree.Insert(theAVLTree.CreateNewNode(1.29431,1));
theAVLTree.PrintTree();
// Add 70
Print("Adding Node 1.29445");
theAVLTree.Insert(theAVLTree.CreateNewNode(1.29445,2));
theAVLTree.PrintTree();
// Add 90
Print("Adding Node 1.29433 to trigger test of Case 1 to right. Root is ancester.");
theAVLTree.Insert(theAVLTree.CreateNewNode(1.29433,3));
theAVLTree.PrintTree();
Print("END TESTING CASE 1");
delete theAVLTree;
This is MQL4/MQL5 Code, but the language more or less reflects CPP.
Source for both Cpp & header file:
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property strict
class AVLTreeNode
{
public:
double value;
int index;
// Other data fields can be inserted here
AVLTreeNode *left;
AVLTreeNode *right;
AVLTreeNode *parent;
char balanceFactor;
};
class AVLTree
{
private:
AVLTreeNode *root;
public:
AVLTree(); // Constructor
~AVLTree(); // Destructor
void Insert(AVLTreeNode *n);
void restoreAVL(AVLTreeNode *&ancestor, AVLTreeNode *&newNode);
void adjustBalanceFactors(AVLTreeNode *&end, AVLTreeNode *&_start);
void rotateLeft(AVLTreeNode *&n);
void rotateRight(AVLTreeNode *&n);
void adjustLeftRight(AVLTreeNode *&end, AVLTreeNode *&_start);
void adjustRightLeft(AVLTreeNode *&end, AVLTreeNode *&_start);
AVLTreeNode* CreateNewNode(double key,int index);
void PrintTree();
void FindNearest(double value,AVLTreeNode* &result[]);
private:
void ClearTree(AVLTreeNode *&n);
void Print(AVLTreeNode *&n);
AVLTreeNode* FindNearestHelper(AVLTreeNode* &pRoot, double value);
};
AVLTree::AVLTree()
{
root = NULL; // Initialize root to NULL
}
//------------------------------------------------------------------
// Class destructor
//------------------------------------------------------------------
AVLTree::~AVLTree()
{
// _start recursive destruction of tree
ClearTree(root);
}
//------------------------------------------------------------------
// ClearTree()
// Recursively delete all node in the tree.
//------------------------------------------------------------------
void AVLTree::ClearTree(AVLTreeNode *&n)
{
if(n != NULL)
{
ClearTree(n.left); // Recursively clear the left sub-tree
ClearTree(n.right); // Recursively clear the right sub-tree
delete n; // Delete this node
}
}
void AVLTree::Insert(AVLTreeNode *newNode)
{
AVLTreeNode *temp, *back, *ancestor;
temp = root;
back = NULL;
ancestor = NULL;
// Check for empty tree first
if(root == NULL)
{
root = newNode;
return;
}
// Tree is not empty so search for place to insert
while(temp != NULL) // Loop till temp falls out of the tree
{
back = temp;
// Mark ancestor that will be out of balance after
// this node is inserted
if(temp.balanceFactor != '=')
ancestor = temp;
if(newNode.value < temp.value)
temp = temp.left;
else
temp = temp.right;
}
// temp is now NULL
// back points to parent node to attach newNode to
// ancestor points to most recent out of balance ancestor
newNode.parent = back; // Set parent
if(newNode.value < back.value) // Insert at left
{
back.left = newNode;
}
else // Insert at right
{
back.right = newNode;
}
// Now call function to restore the tree's AVL property
restoreAVL(ancestor, newNode);
}
//------------------------------------------------------------------
// restoreAVL()
// Restore the AVL quality after inserting a new node.
// #param ancestor – most recent node back up the tree that is
// now out of balance.
// #param newNode– the newly inserted node.
//------------------------------------------------------------------
void AVLTree::restoreAVL(AVLTreeNode *&ancestor, AVLTreeNode *&newNode)
{
//--------------------------------------------------------------------------------
// Case 1: ancestor is NULL, i.e. balanceFactor of all ancestors' is '='
//--------------------------------------------------------------------------------
if(ancestor == NULL)
{
if(newNode.value < root.value) // newNode inserted to left of root
root.balanceFactor = 'L';
else
root.balanceFactor = 'R'; // newNode inserted to right of root
// Adjust the balanceFactor for all nodes from newNode back up to root
adjustBalanceFactors(root, newNode);
}
//--------------------------------------------------------------------------------
// Case 2: Insertion in opposite subtree of ancestor's balance factor, i.e.
// ancestor.balanceFactor = 'L' AND Insertion made in ancestor's right subtree
// OR
// ancestor.balanceFactor = 'R' AND Insertion made in ancestor's left subtree
//--------------------------------------------------------------------------------
else if(((ancestor.balanceFactor == 'L') && (newNode.value > ancestor.value)) ||
((ancestor.balanceFactor == 'R') && (newNode.value < ancestor.value)))
{
ancestor.balanceFactor = '=';
// Adjust the balanceFactor for all nodes from newNode back up to ancestor
adjustBalanceFactors(ancestor, newNode);
}
//--------------------------------------------------------------------------------
// Case 3: ancestor.balanceFactor = 'R' and the node inserted is
// in the right subtree of ancestor's right child
//--------------------------------------------------------------------------------
else if((ancestor.balanceFactor == 'R') && (newNode.value > ancestor.right.value))
{
ancestor.balanceFactor = '='; // Reset ancestor's balanceFactor
rotateLeft(ancestor); // Do single left rotation about ancestor
// Adjust the balanceFactor for all nodes from newNode back up to ancestor's parent
adjustBalanceFactors(ancestor.parent, newNode);
}
//--------------------------------------------------------------------------------
// Case 4: ancestor.balanceFactor is 'L' and the node inserted is
// in the left subtree of ancestor's left child
//--------------------------------------------------------------------------------
else if((ancestor.balanceFactor == 'L') && (newNode.value < ancestor.left.value))
{
ancestor.balanceFactor = '='; // Reset ancestor's balanceFactor
rotateRight(ancestor); // Do single right rotation about ancestor
// Adjust the balanceFactor for all nodes from newNode back up to ancestor's parent
adjustBalanceFactors(ancestor.parent, newNode);
}
//--------------------------------------------------------------------------------
// Case 5: ancestor.balanceFactor is 'L' and the node inserted is
// in the right subtree of ancestor's left child
//--------------------------------------------------------------------------------
else if((ancestor.balanceFactor == 'L') && (newNode.value > ancestor.left.value))
{
// Perform double right rotation (actually a left followed by a right)
rotateLeft(ancestor.left);
rotateRight(ancestor);
// Adjust the balanceFactor for all nodes from newNode back up to ancestor
adjustLeftRight(ancestor, newNode);
}
//--------------------------------------------------------------------------------
// Case 6: ancestor.balanceFactor is 'R' and the node inserted is
// in the left subtree of ancestor's right child
//--------------------------------------------------------------------------------
else
{
// Perform double left rotation (actually a right followed by a left)
rotateRight(ancestor.right);
rotateLeft(ancestor);
adjustRightLeft(ancestor, newNode);
}
}
//------------------------------------------------------------------
// Adjust the balance factor in all nodes from the inserted node's
// parent back up to but NOT including a designated end node.
// #param end– last node back up the tree that needs adjusting
// #param _start – node just inserted
//------------------------------------------------------------------
void AVLTree::adjustBalanceFactors(AVLTreeNode *&end, AVLTreeNode *&_start)
{
AVLTreeNode *temp = _start.parent; // Set _starting point at _start's parent
while(temp != end)
{
if(_start.value < temp.value)
temp.balanceFactor = 'L';
else
temp.balanceFactor = 'R';
temp = temp.parent;
} // end while
}
//------------------------------------------------------------------
// rotateLeft()
// Perform a single rotation left about n. This will rotate n's
// parent to become n's left child. Then n's left child will
// become the former parent's right child.
//------------------------------------------------------------------
void AVLTree::rotateLeft(AVLTreeNode *&n)
{
AVLTreeNode *temp = n.right; //Hold pointer to n's right child
n.right = temp.left; // Move temp 's left child to right child of n
if(temp.left != NULL) // If the left child does exist
temp .left.parent = n;// Reset the left child's parent
if(n.parent == NULL) // If n was the root
{
root = temp; // Make temp the new root
temp.parent = NULL; // Root has no parent
}
else if(n.parent.left == n) // If n was the left child of its' parent
n.parent.left = temp; // Make temp the new left child
else // If n was the right child of its' parent
n.parent.right = temp;// Make temp the new right child
if(temp!=n)
{
temp.left = n; // Move n to left child of temp
n.parent = temp; // Reset n's parent
}
}
//------------------------------------------------------------------
// rotateRight()
// Perform a single rotation right about n. This will rotate n's
// parent to become n's right child. Then n's right child will
// become the former parent's left child.
//------------------------------------------------------------------
void AVLTree::rotateRight(AVLTreeNode *&n)
{
AVLTreeNode *temp = n.left; //Hold pointer to temp
n.left = temp.right; // Move temp's right child to left child of n
if(temp.right != NULL) // If the right child does exist
temp.right.parent = n; // Reset right child's parent
if(n.parent == NULL) // If n was root
{
root = temp; // Make temp the root
temp.parent = NULL; // Root has no parent
}
else if(n.parent.left == n) // If was the left child of its' parent
n.parent.left = temp; // Make temp the new left child
else // If n was the right child of its' parent
n.parent.right = temp; // Make temp the new right child
temp.right = n; // Move n to right child of temp
n.parent = temp; // Reset n's parent
}
//------------------------------------------------------------------
// adjustLeftRight()
// #param end- last node back up the tree that needs adjusting
// #param _start - node just inserted
//------------------------------------------------------------------
void AVLTree::adjustLeftRight(AVLTreeNode *&end, AVLTreeNode *&_start)
{
if(end == root)
end.balanceFactor = '=';
else if(_start.value < end.parent.value)
{
end.balanceFactor = 'R';
adjustBalanceFactors(end.parent.left, _start);
}
else
{
end.balanceFactor = '=';
end.parent.left.balanceFactor = 'L';
adjustBalanceFactors(end, _start);
}
}
//------------------------------------------------------------------
// adjustRightLeft
// #param end- last node back up the tree that needs adjusting
// #param _start - node just inserted
//------------------------------------------------------------------
void AVLTree::adjustRightLeft(AVLTreeNode *&end, AVLTreeNode *&_start)
{
if(end == root)
end.balanceFactor = '=';
else if(_start.value > end.parent.value)
{
end.balanceFactor = 'L';
adjustBalanceFactors(end.parent.right, _start);
}
else
{
end.balanceFactor = '=';
end.parent.right.balanceFactor = 'R';
adjustBalanceFactors(end, _start);
}
}
//------------------------------------------------------------------
// PrintTree()
// Intiate a recursive traversal to print the tree
//------------------------------------------------------------------
void AVLTree::PrintTree()
{
Print("Printing the tree...");
Print("Root Node: "+ string(root.value) +" balanceFactor is "+string(root.balanceFactor));
Print(root);
}
//------------------------------------------------------------------
// Print()
// Perform a recursive traversal to print the tree
//------------------------------------------------------------------
void AVLTree::Print(AVLTreeNode *&n)
{
if(n != NULL)
{
Print("Node: "+ string(n.value) + " balanceFactor is "+ string(n.balanceFactor) + "");
if(n.left != NULL)
{
Print(" moving left");
Print(n.left);
Print("Returning to Node"+ string(n.value) + " from its' left subtree");
}
else
{
Print(" left subtree is empty");
}
Print("Node: "+ string(n.value) + " balanceFactor is "+ string(n.balanceFactor) + "");
if(n.right != NULL)
{
Print(" moving right");
Print(n.right);
Print("Returning to Node "+ string(n.value) + " from its' right subtree");
}
else
{
Print(" right subtree is empty");
}
}
}
AVLTreeNode* AVLTree::FindNearestHelper(AVLTreeNode* &pRoot, double value)
{
AVLTreeNode* pClosest = NULL;
double minDistance = 1.7976931348623159*MathPow(10,308); // = DBL_MAX; // SYSTEM CONST
AVLTreeNode* pNode = pRoot;
while(pNode != NULL){
double distance = MathAbs(pNode.value - value);
if(distance < minDistance){
minDistance = distance;
pClosest = pNode;
}
if(distance == 0)
break;
if(pNode.value > value)
pNode = pNode.left;
else if(pNode.value < value)
pNode = pNode.right;
}
return pClosest;
}
void AVLTree::FindNearest(double value,AVLTreeNode* &result[])
{
AVLTreeNode* nearest= FindNearestHelper(root,value);
if(nearest!=NULL)
{
int rSize=0;
rSize=rSize+1;
ArrayResize(result,rSize);
result[rSize-1]=nearest;
AVLTreeNode* nParent=nearest.parent;
AVLTreeNode* nLeft=nearest.left;
AVLTreeNode* nRight=nearest.right;
if(nearest.value>value)
{
if(nLeft!=NULL) nearest=nLeft;
else nearest=nParent;
}
else
{
if(nRight!=NULL)nearest=nRight;
else nearest=nParent;
}
if(nearest!=NULL)
{
rSize=rSize+1;
ArrayResize(result,rSize);
result[rSize-1]=nearest;
}
}
}
//---------------------------------------------
// Create a new tree node with the given key
//---------------------------------------------
AVLTreeNode* AVLTree::CreateNewNode(double key,int ind)
{
AVLTreeNode *temp = new AVLTreeNode();
temp.index = ind;
temp.value = key;
temp.left = NULL;
temp.right = NULL;
temp.parent = NULL;
temp.balanceFactor = '=';
return temp;
}
More details as per request:
Test MQL Script:
//+------------------------------------------------------------------+
//| StackHelp.mq4 |
//| Copyright 2016, MetaQuotes Software Corp. |
//| https://www.mql5.com |
//+------------------------------------------------------------------+
#property copyright "Copyright 2016, MetaQuotes Software Corp."
#property link "https://www.mql5.com"
#property version "1.00"
#property strict
#include <Custom\AVLTree.mqh>
//+
//+------------------------------------------------------------------+
//| Script program start function |
//+------------------------------------------------------------------+
void OnStart()
{
//---
AVLTree *theAVLTree;
theAVLTree = new AVLTree();
Print("TESTING CASE 1");
// Add 1.29567
Print("Adding Node 1.29567");
theAVLTree.Insert(theAVLTree.CreateNewNode(1.29567,0));
theAVLTree.PrintTree();
// Add 1.29431
Print("Adding Node 1.29431 to trigger test of Case 1 to left. Root is ancester.");
theAVLTree.Insert(theAVLTree.CreateNewNode(1.29431,1));
theAVLTree.PrintTree();
// Add 1.29445
Print("Adding Node 1.29445");
theAVLTree.Insert(theAVLTree.CreateNewNode(1.29445,2));
theAVLTree.PrintTree();
// Add 1.2943
Print("Adding Node 1.29433 to trigger test of Case 1 to right. Root is ancester.");
theAVLTree.Insert(theAVLTree.CreateNewNode(1.29433,3));
theAVLTree.PrintTree();
Print("END TESTING CASE 1");
delete theAVLTree;
Print("END TESTING CASE 1");
delete theAVLTree;
}
Terminal Output:

My suspect is an asymmetry in :rotateLeft() vs :rotateRight() class-methods.
The former contains an avoidance of singularity/circular-ref's, the latter does not.
void AVLTree::rotateLeft( AVLTreeNode *&n )
{
AVLTreeNode *temp = n.right; // Hold pointer to n's right child
n.right = temp.left; // Move temp 's left child to right child of n
if ( temp.left != NULL ) // If the left child does exist
temp.left.parent = n; // Reset the left child's parent
if ( n.parent == NULL ) // If n was the root
{ root = temp; // Make temp the new root
temp.parent = NULL; // Root has no parent
}
else if ( n.parent.left == n ) // If n was the left child of its' parent
n.parent.left = temp; // Make temp the new left child
else // If n was the right child of its' parent
n.parent.right = temp; // Make temp the new right child
if ( temp != n ) // If !n ( avoid ( n.parent == n ) + ( n.left == n ) singularities / circulars )
{
temp.left = n; // Move n to left child of temp
n.parent = temp; // Reset n's parent
}
}
+ a few tiny details commented below:
#property copyright "Copyright 2016, VyshuRam, VOLVO.COM"
#property link "https://www.volvo.com"
#property strict
class AVLTreeNode
{
public:
double value;
int index;
// ---------------------------------- // Other data fields can be inserted here
AVLTreeNode* left;
AVLTreeNode* right;
AVLTreeNode* parent;
char balanceFactor;
};
class AVLTree
{
private:
AVLTreeNode* root;
public:
AVLTree(); // Constructor
~AVLTree(); // Destructor
void Insert( AVLTreeNode* n );
void restoreAVL( AVLTreeNode* &ancestor,
AVLTreeNode* &newNode
);
void adjustBalanceFactors( AVLTreeNode* &end,
AVLTreeNode* &_start
);
void rotateLeft( AVLTreeNode* &n );
void rotateRight( AVLTreeNode* &n );
void adjustLeftRight( AVLTreeNode* &end,
AVLTreeNode* &_start
);
void adjustRightLeft( AVLTreeNode* &end,
AVLTreeNode* &_start
);
AVLTreeNode* CreateNewNode( double key,
int index );
void PrintTree();
void FindNearest( double value,
AVLTreeNode* &result[]
);
private:
void ClearTree( AVLTreeNode* &n );
void Print( AVLTreeNode* &n );
AVLTreeNode* FindNearestHelper( AVLTreeNode* &pRoot,
double value
);
};
AVLTree::AVLTree()
{
root = NULL; // Initialize root to NULL
}
//------------------------------------------------------------------
// Class destructor
//------------------------------------------------------------------
AVLTree::~AVLTree()
{
ClearTree( root ); // start recursive destruction of tree
}
//------------------------------------------------------------------
// ClearTree()
// Recursively delete all node in the tree.
//------------------------------------------------------------------
void AVLTree::ClearTree( AVLTreeNode *&n )
{
if ( n != NULL )
{
ClearTree( n.left ); // Recursively clear the left sub-tree
ClearTree( n.right ); // Recursively clear the right sub-tree
delete n; // Delete this node
}
}
void AVLTree::Insert( AVLTreeNode *newNode )
{
AVLTreeNode *temp, *back, *ancestor;
temp = root;
back = NULL;
ancestor = NULL;
if ( root == NULL ) // Check for empty tree first
{
root = newNode;
return;
}
// // Tree is not empty so search for place to insert
while ( temp != NULL ) // Loop till temp falls out of the tree
{
back = temp; // begins with temp == root
// Mark ancestor that will be out of balance after this node is inserted
if ( temp.balanceFactor != '=' ) ancestor = temp;
if ( newNode.value < temp.value ) temp = temp.left;
else temp = temp.right;
}
// temp is now NULL ( while(){..}-terminated )
// back points to parent node to attach a newNode to
// ancestor points to most recent out of balance ancestor
newNode.parent = back; // Set parent
if ( newNode.value < back.value ) // Insert at left
{
back.left = newNode;
}
else // Insert at right
{
back.right = newNode;
}
// Now call function to restore the tree's AVL property
restoreAVL( ancestor, newNode );
}
//------------------------------------------------------------------
// restoreAVL()
// Restore the AVL quality after inserting a new node.
// #param ancestor – most recent node back up the tree that is
// now out of balance.
// #param newNode– the newly inserted node.
//------------------------------------------------------------------
void AVLTree::restoreAVL( AVLTreeNode *&ancestor, AVLTreeNode *&newNode )
{
//--------------------------------------------------------------------------------
// Case 1: ancestor is NULL, i.e. balanceFactor of all ancestors' is '='
//--------------------------------------------------------------------------------
if ( ancestor == NULL )
{
if ( newNode.value < root.value )
root.balanceFactor = 'L'; // newNode inserted to left of root
else root.balanceFactor = 'R'; // newNode inserted to right of root
adjustBalanceFactors( root, // Adjust the balanceFactor
newNode // for all nodes
); // from newNode back up to root
}
//--------------------------------------------------------------------------------
// Case 2: Insertion in opposite subtree of ancestor's balance factor, i.e.
// ancestor.balanceFactor = 'L' AND Insertion made in ancestor's right subtree
// OR
// ancestor.balanceFactor = 'R' AND Insertion made in ancestor's left subtree
//--------------------------------------------------------------------------------
else if ( ( ( ancestor.balanceFactor == 'L' )
&& ( ancestor.value < newNode.value )
)
|| ( ( ancestor.balanceFactor == 'R' )
&& ( ancestor.value > newNode.value )
)
)
{
ancestor.balanceFactor = '=';
adjustBalanceFactors( ancestor, // Adjust the balanceFactor
newNode // for all nodes
); // from newNode back up to ancestor
}
//--------------------------------------------------------------------------------
// Case 3: ancestor.balanceFactor = 'R' and the node inserted is
// in the right subtree of ancestor's right child
//--------------------------------------------------------------------------------
else if ( ( ancestor.balanceFactor == 'R' )
&& ( ancestor.right.value < newNode.value )
)
{
ancestor.balanceFactor = '='; // Reset ancestor's balanceFactor
rotateLeft( ancestor ); // Do single left rotation about ancestor
adjustBalanceFactors( ancestor.parent, // Adjust the balanceFactor
newNode // for all nodes
); // from newNode back up to ancestor's parent
}
//--------------------------------------------------------------------------------
// Case 4: ancestor.balanceFactor is 'L' and the node inserted is
// in the left subtree of ancestor's left child
//--------------------------------------------------------------------------------
else if ( ( ancestor.balanceFactor == 'L' )
&& ( ancestor.left.value > newNode.value )
)
{
ancestor.balanceFactor = '='; // Reset ancestor's balanceFactor
rotateRight( ancestor ); // Do single right rotation about ancestor
adjustBalanceFactors( ancestor.parent, // Adjust the balanceFactor
newNode // for all nodes
); // from newNode back up to ancestor's parent
}
//--------------------------------------------------------------------------------
// Case 5: ancestor.balanceFactor is 'L' and the node inserted is
// in the right subtree of ancestor's left child
//--------------------------------------------------------------------------------
else if ( ( ancestor.balanceFactor == 'L' )
&& ( ancestor.left.value < newNode.value )
)
{
rotateLeft( ancestor.left ); // Perform double right rotation
rotateRight( ancestor ); // (actually a left followed by a right)
adjustLeftRight( ancestor, // Adjust the balanceFactor
newNode // for all nodes
); // from newNode back up to ancestor
}
//--------------------------------------------------------------------------------
// Case 6: ancestor.balanceFactor is 'R' and the node inserted is
// in the left subtree of ancestor's right child
//--------------------------------------------------------------------------------
else
{
rotateRight( ancestor.right ); // Perform double left rotation
rotateLeft( ancestor ); // (actually a right followed by a left)
adjustRightLeft( ancestor, // Adjust the balanceFactor
newNode // for all nodes
); // from newNode back up to ancestor
}
}
//------------------------------------------------------------------
// Adjust the balance factor in all nodes from the inserted node's
// parent back up to but NOT including a designated end node.
// #param end– last node back up the tree that needs adjusting
// #param _start – node just inserted
//------------------------------------------------------------------
void AVLTree::adjustBalanceFactors( AVLTreeNode *&end, AVLTreeNode *&_start )
{
AVLTreeNode *temp = _start.parent; // Set _starting point at _start's parent
while ( temp != end )
{
if ( _start.value < temp.value ) temp.balanceFactor = 'L';
else temp.balanceFactor = 'R';
temp = temp.parent;
} // end while
}
//------------------------------------------------------------------
// rotateLeft()
// Perform a single rotation left about n. This will rotate n's
// parent to become n's left child. Then n's left child will
// become the former parent's right child.
//------------------------------------------------------------------
void AVLTree::rotateLeft( AVLTreeNode *&n )
{
AVLTreeNode *temp = n.right; // Hold pointer to n's right child
n.right = temp.left; // Move temp 's left child to right child of n
if ( temp.left != NULL ) // If the left child does exist
temp.left.parent = n; // Reset the left child's parent
if ( n.parent == NULL ) // If n was the root
{ root = temp; // Make temp the new root
temp.parent = NULL; // Root has no parent
}
else if ( n.parent.left == n ) // If n was the left child of its' parent
n.parent.left = temp; // Make temp the new left child
else // If n was the right child of its' parent
n.parent.right = temp; // Make temp the new right child
if ( temp != n ) // If !n ( avoid ( n.parent == n ) + ( n.left == n ) singularities / circulars )
{
temp.left = n; // Move n to left child of temp
n.parent = temp; // Reset n's parent
}
}
//------------------------------------------------------------------
// rotateRight()
// Perform a single rotation right about n. This will rotate n's
// parent to become n's right child. Then n's right child will
// become the former parent's left child.
//------------------------------------------------------------------
void AVLTree::rotateRight( AVLTreeNode *&n )
{
AVLTreeNode *temp = n.left; // Hold pointer to temp
n.left = temp.right; // Move temp's right child to left child of n
if ( temp.right != NULL ) // If the right child does exist
temp.right.parent = n; // Reset right child's parent
if ( n.parent == NULL ) // If n was root
{ root = temp; // Make temp the root
temp.parent = NULL; // Root has no parent
}
else if ( n.parent.left == n ) // If was the left child of its' parent
n.parent.left = temp; // Make temp the new left child
else // If n was the right child of its' parent
n.parent.right = temp; // Make temp the new right child
temp.right = n; // Move n to right child of temp
n.parent = temp; // Reset n's parent
}
//------------------------------------------------------------------
// adjustLeftRight()
// #param end- last node back up the tree that needs adjusting
// #param _start - node just inserted
//------------------------------------------------------------------
void AVLTree::adjustLeftRight( AVLTreeNode *&end,
AVLTreeNode *&_start
)
{
if ( end == root )
end.balanceFactor = '=';
else if ( _start.value < end.parent.value )
{
end.balanceFactor = 'R';
adjustBalanceFactors( end.parent.left, _start );
}
else
{
end.balanceFactor = '=';
end.parent.left.balanceFactor = 'L';
adjustBalanceFactors( end, _start );
}
}
//------------------------------------------------------------------
// adjustRightLeft
// #param end- last node back up the tree that needs adjusting
// #param _start - node just inserted
//------------------------------------------------------------------
void AVLTree::adjustRightLeft( AVLTreeNode *&end,
AVLTreeNode *&_start
)
{
if ( end == root )
end.balanceFactor = '=';
else if ( _start.value > end.parent.value )
{
end.balanceFactor = 'L';
adjustBalanceFactors( end.parent.right, _start );
}
else
{
end.balanceFactor = '=';
end.parent.right.balanceFactor = 'R';
adjustBalanceFactors( end, _start );
}
}
//------------------------------------------------------------------
// PrintTree()
// Intiate a recursive traversal to print the tree
//------------------------------------------------------------------
void AVLTree::PrintTree()
{
Print( "Printing the tree..." );
Print( "Root Node: " + string( root.value ) +" balanceFactor is " + string( root.balanceFactor ) );
Print( root );
}
//------------------------------------------------------------------
// Print()
// Perform a recursive traversal to print the tree
//------------------------------------------------------------------
void AVLTree::Print( AVLTreeNode *&n )
{
if ( n != NULL )
{
Print( "Node: " + string( n.value ) + " balanceFactor is "+ string( n.balanceFactor ) + "" );
if ( n.left != NULL )
{
Print( " moving left" );
Print( n.left );
Print( "Returning to Node" + string( n.value ) + " from its' left subtree" );
}
else
{
Print( " left subtree is empty" );
}
Print( "Node: " + string( n.value ) + " balanceFactor is " + string( n.balanceFactor ) + "" );
if ( n.right != NULL )
{
Print( " moving right" );
Print( n.right );
Print( "Returning to Node " + string( n.value ) + " from its' right subtree" );
}
else
{
Print( " right subtree is empty" );
}
}
}
AVLTreeNode* AVLTree::FindNearestHelper( AVLTreeNode* &pRoot, double value )
{
AVLTreeNode* pClosest = NULL;
double minDistance = 1.7976931348623159 * MathPow( 10, 308 ); // = DBL_MAX; // SYSTEM CONST
AVLTreeNode* pNode = pRoot;
while ( pNode != NULL ){
double distance = MathAbs( pNode.value - value );
if ( minDistance > distance ){
minDistance = distance;
pClosest = pNode;
}
if ( distance == 0 ) break;
if ( pNode.value > value ) pNode = pNode.left;
else if ( pNode.value < value ) pNode = pNode.right;
}
return pClosest;
}
void AVLTree::FindNearest( double value, AVLTreeNode* &result[] )
{
AVLTreeNode* nearest= FindNearestHelper( root, value );
if ( nearest != NULL )
{
int rSize = 0; // ?| rSize = 1; ...........
rSize = rSize + 1; // ?|
ArrayResize( result, rSize );
result[rSize-1] = nearest;
AVLTreeNode* nParent = nearest.parent;
AVLTreeNode* nLeft = nearest.left;
AVLTreeNode* nRight = nearest.right;
if ( nearest.value > value )
{
if ( nLeft != NULL ) nearest = nLeft;
else nearest = nParent;
}
else
{
if ( nRight != NULL ) nearest = nRight;
else nearest = nParent;
}
if ( nearest != NULL )
{
rSize = rSize + 1;
ArrayResize( result, rSize );
result[rSize-1] = nearest;
}
}
}
//---------------------------------------------
// Create a new tree node with the given key
//---------------------------------------------
AVLTreeNode* AVLTree::CreateNewNode( double key,int ind )
{
AVLTreeNode *temp = new AVLTreeNode();
temp.index = ind;
temp.value = key;
temp.left = NULL;
temp.right = NULL;
temp.parent = NULL;
temp.balanceFactor = '=';
return temp;
}

Related

Complete Binary Tree swapping child and parent bug

I'm doing a project for school and I have a weird bug.
I'm implementing a Complete Binary Tree and I have trouble with the swapping of a node with his parent.
During my testing I found 1 case is not working properly.
This :
All of the other swap work fine except in that case
The structure of my tree is as such
typedef struct TreeNode {
void * data;
struct TreeNode * left;
struct TreeNode * right;
struct TreeNode * parent;
} TNode;
typedef struct CompleteBinaryTree {
TNode * root;
TNode * last;
int numelm;
} CBTree;
CBTree * newCBTree(void)
{
CBTree * ret = malloc(sizeof(CBTree));
if( ret )
{
ret->root = NULL;
ret->last = NULL;
ret->numelm = 0;
}
}
TNode * newTNode( void * data )
{
TNode *ret = malloc(sizeof(TNode));
if( ret )
{
ret->data = data;
ret->parent = ret->left = ret->right = NULL;
}
return ret;
}
This is my swapping function :
void CBTreeSwap(CBTree* tree, TNode* parent, TNode* child)
{
assert(parent != NULL && child != NULL && (child == parent->left || child == parent->right));
if (child == tree->last)
tree->last = parent;
if(child == parent->left)
{
if(child->left != NULL)
child->left->parent = parent;
parent->left = child->left;
child->left = parent;
if (child->right != NULL)
child->right->parent = parent;
if (parent->right != NULL)
parent->right->parent = child;
TNode * tmp = child->right;
child->right = parent->right;
parent->right = tmp;
if (parent != tree->root)
{
parent->parent->left = child;
child->parent = parent->parent;
parent->parent = child;
}
else
{
child->parent = NULL;
tree->root = child;
parent->parent = child;
}
}
else
{
if(child->right != NULL)
child->right->parent = parent;
parent->right = child->right;
child->right = parent;
if(child->left != NULL)
child->left->parent = parent;
if(parent->left != NULL)
parent->left->parent = child;
TNode * tmp = child->left;
child->left = parent->left;
parent->left = tmp;
if(parent != tree->root)
{
parent->parent->right = child;
child->parent = parent->parent;
parent->parent = child;
}
else
{
child->parent = NULL;
tree->root = child;
parent->parent = child;
}
}
}
To insert in the tree in use this :
void CBTreeInsert(CBTree* tree, void* data)
{
TNode * tmp = newTNode(data);
TNode * curr = tree->last;
if(tree->root == NULL)
{ //empty
tree->root = tmp;
}
else if(tree->last == tree->root)
{ //one node
tree->last->left = tmp;
tmp->parent = tree->root;
}
else if(tree->last->parent->right == NULL)
{ //general
tree->last->parent->right = tmp;
tmp->parent = tree->last->parent;
}
else if (tree->last == tree->last->parent->right)
{ //degenarated
curr = tree->last->parent ;
while (1)
{
if (curr == tree->root)
break ;
if (curr == curr->parent->left)
{
curr = curr->parent->right ;
assert(curr != NULL) ;
break ;
}
curr = curr->parent ;
}
while (curr->left != NULL)
{
assert(curr->right != NULL) ;
curr = curr->left ;
}
assert(curr->right == NULL) ;
tmp->parent = curr ;
curr->left = tree->last = tmp;
}
else
{
fprintf(stderr,"Error\n");
}
tree->last = tmp;
tree->numelm++;
}
So I build my test like this :
void main(){
int * i[15], j;
CBTree * tree = newCBTree(); //create tree
for(j=0; j<15; j++)
{
i[j] = malloc(sizeof(int));
*(i[j]) = j+1;
CBTreeInsert(tree, (int*) i[j]);
}
//All these work
CBTreeSwap(T, T->root->left, T->root->left->left);
CBTreeSwap(T, T->root, T->root->left);
CBTreeSwap(T, T->root->right, T->root->right->right);
CBTreeSwap(T, T->root, T->root->right);
CBTreeSwap(T, T->last->parent, T->last);
//This one is broken
CBTreeSwap(T, T->root->left, T->root->left->right);
}
When I run that broken test and try to view my tree I get all the branches of my tree followed by a seg fault.
This is just a part of a bigger project if you need more of my code don't hesitate to ask
Thank you !
Your problem generates a tree corruption not only when T->left and T->left->right are swapped (corrupting all T->left subtree left) but also when T->right and T->right->left are swapped.
The problem resides somewhere in CBTreeSwap() function.
Its implementation is actually tricky. It's not easy to understand it, so I'll propose my implementation. I can just say that the root of the problem is probably that somewhere, in the swapping process, you assign some fields of parent/child without paying attention to the fact that they are already changed!
The fix
Please find below the corrected version of CBTreeSwap(). It is correct the distinction between the case in which child is either parent->left or parent->right, but many other actions are common in these two cases. The code is commented.
void CBTreeSwap(CBTree* tree, TNode* parent, TNode* child)
{
assert(parent != NULL && child != NULL && (child == parent->left || child == parent->right));
if (child == tree->last)
tree->last = parent;
/* Save child's childs */
TNode *tmpL = child->left, *tmpR = child->right;
/* Link child (new parent!) to parent's parent */
if(parent != tree->root)
{
TNode *parpar = parent->parent;
child->parent = parpar;
/* Is parent left or right child of his parent? */
if( parent->parent->left == parent)
parpar->left = child;
else
parpar->right = child;
}
else
{
child->parent = NULL;
tree->root = child;
}
/* In order to actually swap nodes we need to know if child is at parent's left or right*/
if(child == parent->left)
{
/* Link parent's other child to child */
parent->right->parent = child;
child->right = parent->right;
/* Link former parent to child's right (making it its new right child) */
child->left = parent;
parent->parent = child;
}
else /* child == parent->right */
{
/* Link parent's other child to child */
parent->left->parent = child;
child->left = parent->left;
/* Link former parent to child's right (making it its new right child) */
child->right = parent;
parent->parent = child;
}
/* Link child's childs to former parent */
parent->left = tmpL;
parent->right = tmpR;
if(tmpL != NULL)
tmpL->parent = parent;
if(tmpR != NULL)
tmpR->parent = parent;
}
So:
Save child's childs.
Link the child (new parent) to old parent's parent, managing the case in which parent is the root node. We need to understand if parent is either at the left or at the right of his parent.
Swap parent and child according to their original mutual position. If we get wrong, we might corrupt a whole subtree.
Restore child's childs
I tested the code above and it worked as expected.
PS: though it is unrelated to this question, consider using an array and a loop for the initialization. The code below behaves like your initialization. Isn't it more elegant?
int * i[15], j;
CBTree * tree = newCBTree(); //create tree
for(j=0; j<15; j++)
{
i[j] = malloc(sizeof(int));
*(i[j]) = j+1;
CBTreeInsert(tree, (int*) i[j]);
}
An alternative solution
But there's an easier solution to achieve your specific goal: why swapping entire subtrees when, at the end of the program, just nodes contents need to be swapped?
So your swap function becomes:
void CBTreeSwap(CBTree* tree, TNode* parent, TNode* child)
{
assert(parent != NULL && child != NULL && (child == parent->left || child == parent->right));
void *tmpData = parent->data;
parent->data = child->data;
child->data = tmpData;
}

LeftRotate failing in AVL Tree at the last point when entering numbers from 1 - 10

I am trying to add numbers in AVL Tree where the node takes (key, value). When entering numbers from (0,0) to (10,10) in the for loop, the code fails when it tries to enter the number (10,10).
Following is the code to insert the node in the tree:
int insert_in_tree_q5(struct AVLTreeNode **node, int key, int value){
//AVLTreeNode *newNode = newAVLTreeNode(key, value);
// if the tree is empty
if(*node == NULL){
*node = newAVLTreeNode(key, value);
}
if(key != (*node)->key){
// insert on left if the data in the key is less than the data in the node.
if (key<(*node)->key){
insert_in_tree_q5(&(*node)->left, key,value);
}
// insert on right if the data in the key is greater than the data in the node.
else if(key>(*node)->key)
{
insert_in_tree_q5(&(*node)->right, key,value);
}
// Update height of the ancestor node
(*node)->height = 1 + max(height((*node)->left), height((*node)->right));
// check balance to see if this node became unbalanced
int balance = getBalance(*node);
//First case to balance the unbalanced node
// Left Left case
if(balance>1 && key<(*node)->left->key){
*node = rightRotate(*node);
}
// Right Right Case
if (balance < -1 && key > (*node)->right->key)
*node = leftRotate(*node);
// Left Right Case
if (balance > 1 && key > (*node)->left->key)
{
(*node)->left = leftRotate((*node)->left);
*node = rightRotate(*node);
}
// Right Left Case
if (balance < -1 && key < (*node)->right->key)
{
(*node)->right = rightRotate((*node)->right);
*node = leftRotate(*node);
}
}
else if(key == (*node)->key){
if (value<(*node)->value){
insert_in_tree_q5(&(*node)->left, key,value);
}
// insert on right if the data in the key is greater than the data in the node.
else if(value>(*node)->value)
{
insert_in_tree_q5(&(*node)->right, key,value);
}
// Update height of the ancestor node
(*node)->height = 1 + max(height((*node)->left), height((*node)->right));
// check balance to see if this node became unbalanced
int balance = getBalance(*node);
//First case to balance the unbalanced node
// Left Left case
if(balance>1 && value<(*node)->left->value){
*node =rightRotate(*node);
}
// Right Right Case
if (balance < -1 && value > (*node)->right->value)
*node =leftRotate(*node);
// Left Right Case
if (balance > 1 && value > (*node)->left->value)
{
(*node)->left = leftRotate((*node)->left);
*node =rightRotate(*node);
}
// Right Left Case
if (balance < -1 && value < (*node)->right->value)
{
(*node)->right = rightRotate((*node)->right);
*node =leftRotate(*node);
}
}else if(key == (*node)->key && value == (*node)->value){
return 0;
}
return 1;
}
The code for Left Rotate is :
struct AVLTreeNode* leftRotate(struct AVLTreeNode *x){
struct AVLTreeNode *y = x->right;
struct AVLTreeNode *T2 = y->left;
// Perform rotation
y->left = x;
x->right = T2;
// Update heights
x->height = max(height(x->left), height(x->right))+1;
y->height = max(height(y->left), height(y->right))+1;
// Return new root
return y;
}
The way I am entering the values in the tree is :
int InsertNode(AVLTree *T, int k, int v)
{
//put your code here
int returnedValue = insert_in_tree_q5(&T->root, k, v);
if(returnedValue==0){
return 0;
}
return 1;
}
tree4=newAVLTree();
j=InsertNode(tree4, 10, 10);
for (i=0; i<15; i++)
{
j=InsertNode(tree4, i, i);
if (j==0) printf("(%d, %d) already exists\n", i, i);
}
The signature of the AVLTreeNode and AVLTree is:
typedef struct AVLTreeNode {
int key; //key of this item
int value; //value (int) of this item
int height; //height of the subtree rooted at this node
struct AVLTreeNode *parent; //pointer to parent
struct AVLTreeNode *left; //pointer to left child
struct AVLTreeNode *right; //pointer to right child
} AVLTreeNode;
AVLTree *newAVLTree()
{
AVLTree *T;
T = malloc(sizeof (AVLTree));
assert (T != NULL);
T->size = 0;
T->root = NULL;
return T;
}
PS: If the item (k,v) already exists, it should return 0 else add it to the tree and return 1.
Any ideas as to why it accepts all the values till (9,9) but fails at (10,10) with error "Thread 1: EXC_BAD_ACCESS (code=1, address=0x18)"
If the item (k,v) already exists, it should return 0 else add it to the tree and return 1
in insert_in_tree_q5 you do :
if(*node == NULL){
*node = newAVLTreeNode(key, value);
}
if(key != (*node)->key){
...CASE A
}
else if(key == (*node)->key){
...CASE B
} else if(key == (*node)->key && value == (*node)->value){
return 0;
}
return 1;
the case else if(key == (*node)->key && value == (*node)->value) is never reach because just before you do else if(key == (*node)->key), you need to reverse their order.
For me when (*node == NULL) you do not have to continue too
Note you already know that if(key != (*node)->key) is false so to test the equality in the two next tests is useless
Finaly your code must be :
if(*node == NULL){
*node = newAVLTreeNode(key, value);
}
else if(key != (*node)->key){
...CASE A
}
else if( value == (*node)->value){
return 0;
}
else {
...CASE B
}
return 1;
In
int InsertNode(AVLTree *T, int k, int v)
{
//put your code here
int returnedValue = insert_in_tree_q5(&T->root, k, v);
if(returnedValue==0){
return 0;
}
return 1;
}
because insert_in_tree_q5 only returns 0 or 1 InsertNode can be simplified to be just
int InsertNode(AVLTree *T, int k, int v)
{
return insert_in_tree_q5(&T->root, k, v);
}

AVL Tree in C with iterative insertion

I'm coding a generic AVL tree as both a challenge to myself and, if I can do it properly, a resource for other CS students out there.
As one usually would, I started by implementing a recursive insertion function, which works. However, due to efficiency, I tried to implement the same function, but iteratively. I searched online and found lots of implementations, but the rest of the code was always too different from mine, which led me to continue attempting to create an implementation from scratch.
These are the relevant defined types:
typedef struct info {
int id;
char name[200];
} data;
typedef struct avl_node {
void * data;
struct avl_node * left;
struct avl_node * right;
int height;
} * avl_node_t;
typedef struct avl_tree {
avl_node_t root;
int num_nodes;
int (*less)(const void * first, const void * second);
int (*key)(const void * data);
} * avl_t;
And as follows is the iterative insertion function (which doesn't work as intended):
avl_node_t
avl_insert(avl_node_t node, void * data)
{
long key1 = 0, key2 = 0;
avl_node_t aux = NULL;
while (1) {
if (node == NULL) {
node = avl_node_create(data);
break;
}
key1 = key((void*)&data);
key2 = key((void*)&(node->data));
aux = node;
if (less((void*)&key1, (void*)&key2))
node = node->left;
else
node = node->right;
}
if (aux != NULL) {
if (less((void*)&key1, (void*)&key2))
aux->right = node;
else if (less((void*)&key2, (void*)&key1))
aux->left = node;
}
node = avl_balance(node);
return node;
}
In which the avl_balance function is defined as such:
static short
balance(avl_node_t node)
{
if (node == NULL)
return 0;
return avl_node_height(node->left) - avl_node_height(node->right);
}
static avl_node_t
avl_balance(avl_node_t node)
{
short balance_factor;
if (node == NULL)
return node;
balance_factor = balance(node);
if (balance_factor > 1)
if (balance(node->left) >= 0)
node = avl_rotRight(node);
else
node = avl_rotLeftRight(node);
else if (balance_factor < -1)
if (balance(node->right) <= 0)
node = avl_rotLeft(node);
else
node = avl_rotRightLeft(node);
else
update_height(node);
return node;
}
This is the code I'm using to test the AVL tree:
int main()
{
data d1 = { 1, "we are number one" };
data d2 = { 2, "boneless pizza" };
data d3 = { 3, "hehe" };
data d4 = { 4, "achoo" };
data d5 = { 5, "I like C" };
data d6 = { 6, "Assembly is cool too" };
data d7 = { 7, "SIGSEGV" };
avl_t tree = avl_create();
avl_node_t root = tree->root;
root = avl_insert(root, (void*)&d1);
traverse(root);
root = avl_insert(root, (void*)&d2);
traverse(root);
root = avl_insert(root, (void*)&d3);
root = avl_insert(root, (void*)&d4);
root = avl_insert(root, (void*)&d5);
root = avl_insert(root, (void*)&d6);
root = avl_insert(root, (void*)&d7);
traverse(root);
free(tree);
exit(0);
}
In which traverse is defined as such:
void visit(void * d)
{
data * my_data = (data*)d;
printf("I am element number %d named %s\n", (*my_data).id, (*my_data).name);
fflush(stdout);
}
void traverse(avl_node_t node)
{
if (node == NULL)
return;
traverse(node->left);
traverse(node->right);
visit(node->data);
}
And finally, this is the output I'm getting from this test:
I am element number 1 named we are number one
I am element number 2 named boneless pizza
I am element number 7 named SIGSEGV
Thank you in advance.
If you do not mind, i implemented it in c++ version.
// In the view of C, just omit the template declaration and replace the class with struct
template<typename T>
class AVL_tree{
private:
class AVL_Node{
public:
T val;
AVL_Node* left;
AVL_Node* right;
AVL_Node* parent;
int height;
// Node Constructor -
AVL_Node():left{nullptr}, right{nullptr}, parent{nullptr}, val{}, height{0}{}
AVL_Node(T val): left{nullptr}, right{nullptr}, parent{nullptr}, height{0}, val{val}{}
};
AVL_Node* root;
short (*cmp_func)(T, T);
// Utility -
void add_child(AVL_Node* prev_nd, AVL_Node* chd_nd){
if(prev_nd == nullptr){
this->root = chd_nd;
return;
}
// update parent pointer first.
switch(cmp_func(chd_nd->val, prev_nd->val)){
case 1:
prev_nd->right = chd_nd;
break;
case 0:
prev_nd->left = chd_nd;
break;
case -1:
cerr << "Warning : The element should not be duplicate." << endl;
return;
default:
cerr << "ERROR_MESSAGE : The self-defin compare func should return triple value (1, 0, -1)." << endl;
return;
}
// update parent pointer of child node
chd_nd->parent = prev_nd;
}
AVL_Node* find_node(T val){
AVL_Node* prev_ptr = nullptr;
for(AVL_Node* tmp_ptr = this->root ; tmp_ptr != nullptr ; ){
prev_ptr = tmp_ptr;
switch(cmp_func(val, tmp_ptr->val)){
case 1:
tmp_ptr = tmp_ptr->right;
break;
case 0:
tmp_ptr = tmp_ptr->left;
break;
case -1:
return prev_ptr;
}
}
// for not find the node, return their parent node.
return prev_ptr;
}
int get_max(int a, int b){ return (a >= b) ? a : b; }
int get_height(AVL_Node* ptr_nd){
if(ptr_nd == nullptr)
return -1;
return ptr_nd->height;
}
int cal_balance(AVL_Node* nd_ptr){ return get_height(nd_ptr->left) - get_height(nd_ptr->right); }
AVL_Node* Right_rotate(AVL_Node* curr_nd){
AVL_Node* lft_chd = curr_nd->left;
AVL_Node* rgt_suc = lft_chd->right;
// Perform rotation
lft_chd->right = curr_nd;
curr_nd->left = rgt_suc;
// update parent pointer of current pointed node and child node
lft_chd->parent = curr_nd->parent;
curr_nd->parent = lft_chd;
if(rgt_suc != nullptr)
rgt_suc->parent = curr_nd;
// Update heights
lft_chd->height = get_max(get_height(lft_chd->left), get_height(lft_chd->right)) + 1;
curr_nd->height = get_max(get_height(curr_nd->left), get_height(curr_nd->right)) + 1;
return lft_chd;
}
AVL_Node* Left_rotate(AVL_Node* curr_nd){
AVL_Node* rgt_chd = curr_nd->right;
AVL_Node* lft_suc = rgt_chd->left;
// Perform rotation
rgt_chd->left = curr_nd;
curr_nd->right = lft_suc;
// update parent pointer of current pointed node and child node
rgt_chd->parent = curr_nd->parent;
curr_nd->parent = rgt_chd;
if(lft_suc != nullptr)
lft_suc->parent = curr_nd;
// Update heights
rgt_chd->height = get_max(get_height(rgt_chd->left), get_height(rgt_chd->right)) + 1;
curr_nd->height = get_max(get_height(curr_nd->left), get_height(curr_nd->right)) + 1;
return rgt_chd;
}
void splice(AVL_Node* ptr_nd){
/* remove node confirm that the ptr_nd have successor in single side.
Case 1. ; Case 2. */
AVL_Node* succsor_nd = (ptr_nd->left != nullptr) ? ptr_nd->left : ptr_nd->right;
if(ptr_nd == this->root){ // for remove the root.
this->root = succsor_nd;
}else{
AVL_Node* par_nd = ptr_nd->parent;
if(par_nd->left == ptr_nd)
par_nd->left = succsor_nd;
else
par_nd->right = succsor_nd;
if(succsor_nd != nullptr) succsor_nd->parent = par_nd;
}
}
public:
enum Order{ // for the order traversal.
pre_order,
post_order,
in_order
};
// Constructor -
AVL_tree():root{nullptr}, cmp_func{&defau_cmp<T>}{}
AVL_tree(short (*def_cmp_func)(T, T)):root{nullptr}, cmp_func{def_cmp_func}{}
// Operation -
void insert(T val){
// BST insertion operation
AVL_Node* prev_nd = find_node(val);
AVL_Node* chd_nd = new AVL_Node(val);
add_child(prev_nd, chd_nd);
// Balance the tree
for(AVL_Node* nd_ptr = prev_nd ; nd_ptr != nullptr ; nd_ptr = nd_ptr->parent){
const int& bf = cal_balance(nd_ptr);
// Left bias unbalance
if( bf > 1 ){
if(val > nd_ptr->left->val)
nd_ptr->left = Left_rotate(nd_ptr->left);
// update parent's pointer
AVL_Node* par_ptr = nd_ptr->parent;
if(par_ptr != nullptr && par_ptr->right == nd_ptr)
par_ptr->right = Right_rotate(nd_ptr);
else if(par_ptr != nullptr && par_ptr->left == nd_ptr)
par_ptr->left = Right_rotate(nd_ptr);
else
Right_rotate(nd_ptr);
// Right bias unbalance
}else if(bf < -1){
if(val < nd_ptr->right->val)
nd_ptr->right = Right_rotate(nd_ptr->right);
// update parent's pointer
AVL_Node* par_ptr = nd_ptr->parent;
if(par_ptr != nullptr && par_ptr->right == nd_ptr)
par_ptr->right = Left_rotate(nd_ptr);
else if(par_ptr != nullptr && par_ptr->left == nd_ptr)
par_ptr->left = Left_rotate(nd_ptr);
else // nd_ptr equal root
Left_rotate(nd_ptr);
// else, the sub-tree is already balanced
}else{
nd_ptr->height = get_max(get_height(nd_ptr->left), get_height(nd_ptr->right)) + 1;
}
// finally update the new root pointer
if(nd_ptr->parent == nullptr)
this->root = nd_ptr;
}
}
// remove operation is still working on it though.
// Smart_queue just like a queue offer general interface, you can use stl-container.
void BF_print(){
Smart_queue<AVL_Node*> nd_que(this->root);
while(!nd_que.is_empty()){
AVL_Node* tmp_ptr = nd_que.pop();
if(tmp_ptr == nullptr)
continue;
cout << tmp_ptr->val << " ";
nd_que.push(tmp_ptr->left);
nd_que.push(tmp_ptr->right);
}
}
};

Deleting a node from a binary search tree without recursion

I have a binary search tree. I want to delete a node from it:
void deleteANode(struct node *head, int value) {
//let us find the node
struct node *temp = head;
struct node *parent = NULL;
//let us find the node
while (temp != NULL) {
if (value > temp->data) {
parent = temp;
temp = temp->right;
} else
if (value < temp->data) {
parent = temp;
temp = temp->left;
} else {
//let us check for child nodes
//
if (temp->left == NULL && temp->right == NULL) {
printf("Deleting a leaf.\n");
temp = NULL;
printf("Set temp null.\n");
free(temp);
break;
} else
if (temp->left == NULL || temp->right == NULL) {
printf("Deleting a one child.\n");
//one of the child is null
if (temp->left != NULL) {
parent->left = temp->left;
} else {
parent->right = temp->right;
}
free(temp);
} else {
printf("Deleting two child parent.\n");
//both of them are not NULL
//need to find the pre-order successor
struct node *temp2 = temp->right;
while (temp2->left != NULL) {
temp2 = temp2->left;
}
//found the successor.
temp->data = temp2->data;
free(temp);
}
break;
}
}
}
I am trying to delete a leaf node in this block:
if (temp->left == NULL && temp->right == NULL) {
printf("Deleting a leaf.\n");
temp->data = NULL;
printf("Set temp null.\n");
free(temp);
break;
}
But the above code doesn't work.
I am calling the above method:
deleteANode(head, 3);
The preorder traversal is remains same before and after:
5 4 3 10 7 20 Deleting a leaf. Set temp null.
=============== 5 4 3 10 7 20
What am I doing wrong.
Updated as per #pstrjds comments:
if (temp->left == NULL && temp->right == NULL ) {
printf("Deleting a leaf.\n");
parent->left = NULL;
parent->right = NULL;
free(temp);
temp = NULL;
printf("Set temp null.\n");
break;
}
It's working fine for leaf node. Need to work for node with two children.
In the block of code which is deleting a leaf you are not actually freeing the node nor are you updating the parent node to no longer point to it.
if ( temp -> left == NULL && temp -> right == NULL )
{
printf("Deleting a leaf.\n");
if (parent->left == temp)
{
parent->left = NULL;
}
else
{
parent->right = NULL;
}
free(temp);
temp = NULL;
printf("Set temp null.\n");
break;
}
You could actually remove the line temp = NULL and change the break; to a return statement.
Does your code really work?
It should be like this:
printf("Deleting two child parent.\n");
Node* temp2 = temp->right;
while(temp2->left != NULL)
{
parent = temp2;
temp2 = temp2->left;
}
temp->data = temp2->data;
parent->left = NULL;
delete temp2;
return;
Java Solution
// Java program to demonstrate delete operation in binary search tree
class BinarySearchTree
{
/* Class containing left and right child of current node and key value*/
class Node
{
int key;
Node left, right;
public Node(int item)
{
key = item;
left = right = null;
}
}
// Root of BST
Node root;
// Constructor
BinarySearchTree()
{
root = null;
}
// This method mainly calls deleteRec()
void deleteKey(int key)
{
root = deleteRec(root, key);
}
/* A recursive function to insert a new key in BST */
Node deleteRec(Node root, int key)
{ Node x=root;
Node parent =null;
/* Base Case: If the tree is empty */
while(x!=null)
{
if(x.key>key)
{ parent=x;
x=x.left;
}
else if(x.key<key)
{parent=x;
x=x.right;
}
else
{
if(x.left==null&&x.right==null)
{
System.out.println(x.key+"y1");
if(parent.left==x)
parent.left=null;
else if(parent.right==x)
parent.right=null;
x=null;
break;
}
else
{
System.out.println(x.key+"y2");
if(x.left==null)
{
if(parent.right==x)
parent.right=x.right;
else if(parent.left==x)
parent.left=x.right;
System.out.println(x.key+"yes");
x=null;
break;
}
else if(x.right==null)
{
if(parent.left==x)
parent.left=x.left;
else if(parent.right==x)
parent.right=x.left;
x=null;
break;
}
else
{
Node temp=x;
Node px=null;
temp=temp.right;
while(temp.left!=null)
{ px=temp;
temp=temp.left;
}
x.key=temp.key;
if(px.left==temp)
px.left=null;
else if(px.left==temp)
px.right=null;
temp=null;
break;
}
}
}
}
return root;
}
int minValue(Node root)
{
int minv = root.key;
while (root.left != null)
{
minv = root.left.key;
root = root.left;
}
return minv;
}
// This method mainly calls insertRec()
void insert(int key)
{
root = insertRec(root, key);
}
/* A recursive function to insert a new key in BST */
Node insertRec(Node root, int key)
{
/* If the tree is empty, return a new node */
if (root == null)
{
root = new Node(key);
return root;
}
/* Otherwise, recur down the tree */
if (key < root.key)
root.left = insertRec(root.left, key);
else if (key > root.key)
root.right = insertRec(root.right, key);
/* return the (unchanged) node pointer */
return root;
}
// This method mainly calls InorderRec()
void inorder()
{
inorderRec(root);
}
// A utility function to do inorder traversal of BST
void inorderRec(Node root)
{
if (root != null)
{
inorderRec(root.left);
System.out.print(root.key + " ");
inorderRec(root.right);
}
}
// Driver Program to test above functions
public static void main(String[] args)
{
BinarySearchTree tree = new BinarySearchTree();
/* Let us create following BST
50
/ \
30 70
/ \ / \
20 40 60 80 */
tree.insert(50);
tree.insert(30);
tree.insert(20);
tree.insert(40);
tree.insert(70);
tree.insert(60);
tree.insert(80);
System.out.println("Inorder traversal of the given tree");
tree.inorder();
System.out.println("\nDelete 20");
tree.deleteKey(20);
System.out.println("Inorder traversal of the modified tree");
tree.inorder();
System.out.println("\nDelete 30");
tree.deleteKey(30);
System.out.println("Inorder traversal of the modified tree");
tree.inorder();
System.out.println("\nDelete 50");
tree.deleteKey(50);
System.out.println("Inorder traversal of the modified tree");
tree.inorder();
}
}

C program: Binary tree

I need some help with creating a binary tree program. Basically, I have different methods for creating and using a binary tree table (insert, find etc). The methods are called from other classes. Right now I don't think my insert function is working properly since when I print the table out it only shows the last node of the tree.
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define __USE_BSD
#include <string.h>
#include "speller.h"
#include "dict.h"
typedef struct node *tree_ptr;
struct node {
Key_Type element; // only data is the key itself
tree_ptr left, right;
// add anything else that you need
};
struct table {
tree_ptr head; // points to the head of the tree
// add anything else that you need
};
Table initialize_table(/*ignore parameter*/) {
Table newTable = malloc(sizeof(Table));
newTable->head = NULL;
return newTable;
}
void insert_again(Key_Type key, tree_ptr node) {
Key_Type currentKey = node->element;
//printf("%s\n%s", currentKey, key);
int keyCompare = strcmp(key, currentKey);
// Move to the left node.
if (keyCompare < 0) {
//printf("%s\n%s", currentKey, key);
// If left node is empty, create a new node.
if (node->left == NULL) {
tree_ptr newPtr = malloc(sizeof(tree_ptr));
newPtr->element = key;
newPtr->left = NULL;
newPtr->right = NULL;
node->left = newPtr;
} else {
insert_again(key, node->left);
}
}
// Move to the right node.
else if (keyCompare > 0) {
//printf("%s\n%s", currentKey, key);
// If right node is empty, create a new node.
if (node->right == NULL) {
tree_ptr newPtr = malloc(sizeof(tree_ptr));
newPtr->element = key;
newPtr->left = NULL;
newPtr->right = NULL;
node->right = newPtr;
} else {
insert_again(key, node->right);
}
}
}
Table insert(Key_Type key, Table table) {
// if it's a new tree.
if (table->head == NULL) {
tree_ptr headPtr = malloc(sizeof(tree_ptr));
headPtr->element = key;
headPtr->left = NULL;
headPtr->right = NULL;
table->head = headPtr;
//printf("%s", table->head->element);
}
// if the tree already exists
else {
//printf("%s", table->head->element);
insert_again(key, table->head);
}
//printf("%s", table->head->element);
return table;
}
Boolean find_key(Key_Type key, tree_ptr node) {
Key_Type currentKey = node->element;
int keyCompare = strcmp(key, currentKey);
if (node != NULL) {
if (keyCompare == 0) {
return TRUE;
} else
if (keyCompare == -1) {
return find_key(key, node->left);
} else {
return find_key(key, node->right);
}
} else {
return FALSE;
}
}
Boolean find(Key_Type key, Table table) {
return find_key(key, table->head);
}
void print_tree(tree_ptr node) {
if (node == NULL) {
return;
}
print_tree(node->left);
printf("%s\n", node->element);
print_tree(node->right);
}
void print_table(Table table) {
print_tree(table->head);
}
void print_stats(Table table) {
}
You have to search for an empty child node to insert a new node into a tree. Use a pointer to a pointer to notice the empty child node. Apart from this you have to allocate memory for sizeof(struct node)and not for sizeof(struct node*) as you did. In relation to the code I can see, that type of Key_Type is char*. So you have to use strcmp to compare keys and you have to allocate memory and to copy the key into the node.
Boolean insert( Key_Type key, Table table )
{
tree_ptr *ppNode = &(table->head); // pointer to pointer to node (struct node **)
while ( ppNode != NULL )
{
int keyCompare = strcmp( key, (*ppNode)->element );
if ( keyCompare == 0 )
return FALSE; // element with key is already member of tree
if ( keyCompare < 0 )
ppNode = &((*ppNode)->left); // go to left child
else
ppNode = &((*ppNode)->right); // go to right child
}
// now ppNode is either a pointer to an empty child pointer,
// or to table->head if the tree is empty
*ppNode = malloc( sizeof(struct node) ); // allocate new node right to target
(*ppNode)->left = NULL;
(*ppNode)->right = NULL;
(*ppNode)->element = malloc( strlen(key) + 1 );
strcpy( (*ppNode)->element, key );
return TRUE; // new node added successfully
}
Finding a node with key is similar to find an empty child pointer:
Boolean find_key( Key_Type key, Table table )
{
tree_ptr pNode = table->head;
while ( ppNode != NULL )
{
int keyCompare = strcmp( key, pNode->element );
if ( keyCompare == 0 )
return TRUE; // element with key was found
if ( keyCompare < 0 )
pNode = pNode->left; // go to left child
else
pNode = pNode->right; // go to right child
}
return FALSE; // key is not member of tree
}

Resources