The algorithm described in CLRS 3 ed. looks wrong. I tried implement but the insertion not works fine.
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <ctime>
#include <vector>
#include <algorithm>
using namespace std;
const char BLACK = 'B';
const char RED = 'R';
template <class T>
class Node{
public:
Node *left;
Node *right;
Node *parent;
char color;
T key;
Node(T x){
this->left = NULL;
this->right = NULL;
this->parent = NULL;
this->key = x;
this->color = RED;
};
virtual ~Node(){};
};
template <class T>
class RedBlackTree{
private:
int ammount;
int h;
int lastAmmount;
Node<T> *root;
Node<T> *NIL;
void destroy_node(Node<T> *&node);
Node<T> *remove_node(Node<T> *&node, T x); // not imeplemented yet
Node<T> *search_node(Node<T> *&node, T x); // not imeplemented yet
void printInfo(Node<T> *&x);
void printInOrder_node(Node<T> *&node);
void printInLevel_node(Node<T> *&node, int level);
int calculeHeight(Node<T> *&node);
void rotateLeft(Node<T> *&x);
void rotateRight(Node<T> *&y);
void insertFixUp(Node<T> *&x);
public:
RedBlackTree();
virtual ~RedBlackTree();
void destroy();
void insert(T x);
void remove(T x); // not imeplemented yet
Node<T> *search(T x); // not implemented yet
int height();
void printInOrder();
void printInLevel();
};
template <class T>
RedBlackTree<T>::RedBlackTree(){
this->ammount = 0;
this->lastAmmount = -1;
this->h = 0;
this->NIL = new Node<T>(-1);
this->NIL->color = BLACK;
this->NIL->left = this->NIL->right = this->NIL->parent = this->NIL;
this->root = this->NIL;
this->root->color = BLACK;
}
template <class T>
RedBlackTree<T>::~RedBlackTree(){
delete this->root;
}
template <class T>
void RedBlackTree<T>::destroy_node(Node<T> *&node){
if(node != NULL){
this->destroy(node->left);
this->destroy(node->right);
delete node;
}
}
template <class T>
void RedBlackTree<T>::destroy(){
this->destroy_node(this->root);
}
// RB methods
template <class T>
void RedBlackTree<T>::rotateLeft(Node<T> *&x){
Node<T> *y = x->right;
x->right = y->left;
if(y->left != this->NIL)
y->left->parent = x;
y->parent = x->parent;
if(x->parent == this->NIL)
this->root = y;
else if(x == x->parent->left)
x->parent->left = y;
else
x->parent->right = y;
y->left = x;
x->parent = y;
}
template <class T>
void RedBlackTree<T>::rotateRight(Node<T> *&y){
Node<T> *x = y->left;
y->left = x->right;
if(x->right != this->NIL)
x->right->parent = y;
x->parent = y->parent;
if(y->parent == this->NIL)
this->root = x;
else if(y == y->parent->left)
y->parent->left = x;
else
y->parent->right = x;
x->right = y;
y->parent = x;
}
template <class T>
void RedBlackTree<T>::insertFixUp(Node<T> *&z){
Node<T> *y;
while(z != this->root and z->parent->color == RED){
if(z->parent == z->parent->parent->left){
y = z->parent->parent->right;
if(y->color == RED){
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
}
else{
if(z == z->parent->right){
z = z->parent;
this->rotateLeft(z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
this->rotateRight(z->parent->parent);
}
}
else{
y = z->parent->parent->left;
if(y->color == RED){
z->parent->color = BLACK;
y->color = BLACK;
z->parent->parent->color = RED;
z = z->parent->parent;
}
else{
if(z == z->parent->left){
z = z->parent;
this->rotateRight(z);
}
z->parent->color = BLACK;
z->parent->parent->color = RED;
this->rotateLeft(z->parent->parent);
}
}
}
this->root->color = BLACK;
}
template <class T>
void RedBlackTree<T>::insert(T val){
Node<T> *z = new Node<T>(val);
Node<T> *x = this->root;
Node<T> *y = this->NIL;
while(x != this->NIL){
y = x;
if(z->key < x->key)
x = x->left;
else
x = x->right;
}
z->parent = y;
if(y == this->NIL)
this->root = z;
else if(z->key < y->key)
y->left = z;
else
y->right = z;
z->left = this->NIL;
z->right = this->NIL;
z->color = RED;
this->insertFixUp(z);
}
template <class T>
int RedBlackTree<T>::height(){
if(this->lastAmmount == this->ammount)
return this->h;
this->h = this->calculeHeight(this->root);
this->lastAmmount = this->ammount;
return this->h;
}
template <class T>
int RedBlackTree<T>::calculeHeight(Node<T> *&node){
if(node == this->NIL)
return 0;
int l_h = this->calculeHeight(node->left);
int r_h = this->calculeHeight(node->right);
if(l_h > r_h)
return l_h+1;
return r_h+1;
}
template <class T>
void RedBlackTree<T>::printInfo(Node<T> *&x){
cout << "key=";
cout << x->key;
cout << " l->key=";
if( x->left == this->NIL)
cout << "N";
else
cout << x->left->key;
cout << " r->key=";
if( x->right == this->NIL)
cout << "N";
else
cout << x->right->key;
cout << " p->key=";
if( x->parent == this->NIL)
cout << "N";
else
cout << x->parent->key;
cout << " color=" << x->color << endl;
}
template <class T>
void RedBlackTree<T>::printInOrder_node(Node<T> *&node){
if(node != this->NIL){
this->printInOrder_node(node->left);
//cout << " " << node->key;
this->printInfo(node);
this->printInOrder_node(node->right);
}
}
template <class T>
void RedBlackTree<T>::printInOrder(){
this->printInOrder_node(this->root);
}
template <class T>
void RedBlackTree<T>::printInLevel(){
int h = this->height();
for(int i=1; i<=h; i++)
this->printInLevel_node(this->root, i);
}
template <class T>
void RedBlackTree<T>::printInLevel_node(Node<T> *&node, int level){
if(node == this->NIL)
return;
if(level == 1)
this->printInfo(node); //cout << node->key << " ";
else if(level > 1){
this->printInLevel_node(node->left, level-1);
this->printInLevel_node(node->right, level-1);
}
}
int main(){
RedBlackTree<int> *bt = new RedBlackTree<int>();
int v[9] = {11, 2, 14, 1, 7, 15, 5, 8, 4};
for(int i=0; i<9; i++){
int x = v[i];
cout << x << " ";
bt->insert(x);
}
cout << endl;
cout << "In Level:" << endl;
bt->printInLevel();
cout << endl;
delete bt;
return 0;
}
I tried to find some others explanations in previous topics, but not seems to work.
This code is basically equals the pseudocode of the book. The expected result for the main example is in level:
7
/ \
2 11
/ \ / \
1 5 8 14
/ \
4 15
So, what's wrong?
Thanks!
Consider what happens when you add the second node. You start with this:
11 (black)
then add the new node:
11 (black)
/
2 (red)
then then try to fix it up:
template <class T>
void RedBlackTree<T>::insertFixUp(Node<T> *&z){
Node<T> *y;
while(z != this->root and z->parent->color == RED){
...
}
this->root->color = BLACK;
}
Note that since 11 is black to begin with, control never enters the loop, so the call to insertFixUp does nothing. So you're left with a tree with a red leaf, which is not a valid red-black tree. After that, if your code expects to be working on a valid red-black tree, it's liable to go wrong.
There may be other bugs, but you should try to get the two-node tree working before you attempt to add a third node.
Related
I'm having trouble implementing the CLRS method for a Red Black Tree. I'm not able to successful insert and I don't know what I'm doing wrong. I struggle with pointers and it's a topic I'm trying to learn more about (I'm buying a book on Amazon this weekend to learn more). Please help me pin point errors. I'm not receiving error messages, but my code won't run past my RBTInsert function, so I know it's getting stuck there. I call RBT Insert in another function that's not shown, but I didn't show it because I'm convinced my errors are in my pointers and nodes.
enum Color {RED, BLACK};
template <typename T>
struct Node
{
T data;
bool color;
Node<T>* left = nullptr;
Node<T>* right = nullptr;
Node<T>* p = nullptr; //p is parent
}
template <typename T>
class RBT
{
private:
Node<T>* root;
void RotateLeft(Node<T>*, Node<T>*);
void RotateRight(Node<T>*, Node<T>*);
void RBTFixUp(Node<T>*, Node<T>*);
void MakeEmpty(Node<T>* root);
public:
RBT(): root(nullptr){}
~RBT();
void RBTInsert(Node<T>* &root, T data);
};
template <typename T>
void RBT<T>::MakeEmpty(Node<T>* root)
{
while (root != nullptr)
{
delete root;
MakeEmpty(root->left);
MakeEmpty(root->right);
}
}
template <typename T>
RBT<T>::~RBT()
{
MakeEmpty(root);
}
template <typename T>
void RBT<T>::RotateLeft(Node<T>* root, Node<T>* x)
{
Node<T>* y = x->right;
x->right = y->left;
if (y->left != nullptr)
y->left->p = x;
y->p = x->p;
if (x->p == nullptr)
root = y;
else if (x == x->p->left)
x->p->left = y;
else
x->p->right = y;
y->left = x;
x->p = y;
}
template <typename T>
void RBT<T>::RotateRight(Node<T>* root, Node<T>* x)
{
Node<T>* y = x->left;
x->left = y->right;
if (y->right != nullptr)
y->right->p = x;
y->p = x->p;
if (x->p == nullptr)
root = y;
else if (x == x->p->right)
x->p->right = y;
else
x->p->left = y;
y->right= x;
x->p = y;
}
template <typename T>
void RBT<T>::RBTFixUp(Node<T>* root, Node<T>* z)
{
while (z->p->color == RED)
{
if (z->p == z->p->p->left)
{
Node<T>* y = z->p->p->right;
if(y->color == RED)
{
z->p->color = BLACK;
y->color = BLACK;
z->p->p->color = RED;
z = z->p->p;
}else if (z == z->p->right)
{
z = z->p;
RotateLeft(root,z);
}
}else
{
Node<T>* y = z->p->p->left;
if(y->color == RED)
{
z->p->color = BLACK;
y->color = BLACK;
z->p->p->color = RED;
z = z->p->p;
}else if (z == z->p->left)
{
z = z->p;
RotateRight(root,z);
}
}
}
}
template <typename T>
void RBT<T>::RBTInsert(Node<T>* &root, T data)
{
Node<T>* z = nullptr;
z->data = data;
Node<T>* y = nullptr;
Node<T>* x = nullptr;
while (x != nullptr)
{
y = x;
if (z->data < x->data)
x = x->left;
else
x = x->right;
}
z->p = y;
if (y == nullptr)
root = z;
else if (z->data < y->data)
y->left = z;
else
y->right = z;
z->left = nullptr;
z->right = nullptr;
z->color = RED;
RBTFixUp(root,z);
}
I'm currently working through AVL trees and am curious why the output (pre order traversal) is only showing two levels of indentation, as if one of the second order nodes is pointing to three separate 3rd level node. I'm note sure if this is an issue with my print function, or the actual code.
#include <iostream>
#include <list>
#include <vector>
#include <iomanip>
using namespace std;
template <class T>
class BST;
template <class T>
class BSTNode{
T data;
BSTNode<T>* parent;
BSTNode<T>* left;
BSTNode<T>* right;
int height;
public:
BSTNode(T data = T(), BSTNode<T>* parent = nullptr, BSTNode<T>* left = nullptr,
BSTNode<T>* right = nullptr, int height = 0) : data(data), parent(parent), left(left), right(right), height(height){}
friend class BST<T>;
int getSize() const;
};
template <class T>
class BST{
public:
BSTNode<T>* root = nullptr;
BST() {}
~BST();
BST(const BST& rhs) {*this = rhs;};
BST& operator=(const BST& rhs);
void printPreOrder(BSTNode<T>* p, int indent);
void insert(T item, BSTNode<T> * & node);
void remove(BSTNode<T>*& temp); //pass pointer by reference because we will be changing the pointer
void clear(BSTNode<T>*& root); //clears the entire tree;
BST<T>* clone(BSTNode<T>* start);
void rotateRight(BSTNode<T> * & node); //rotate the left child (the left child becomes the parent and parent becomes the right child)
void rotateLeft(BSTNode<T> * & node); //rotate the right child (the right child becomes the parent and the parent becomes the left child)
void doubleRotateRight(BSTNode<T> *& node); //same result as rotate right
void doubleRotateLeft(BSTNode<T> *& node); //same result as rotate left
int height(BSTNode<T> * node); //return height
void balance(BSTNode<T> * &node);
};
template <class T>
int BSTNode<T>::getSize() const {
int count = 1;
if(left != nullptr){
count += left->getSize();
};
if(right != nullptr){
count += right->getSize();
};
return count;
}
template <class T>
void BST<T>::printPreOrder(BSTNode<T>* p, int indent){
if(p) {
if (indent) {
std::cout << std::setw(indent) << '\t';
}
cout<< p->data << "\n ";
if(p->left) printPreOrder(p->left, indent+2);
if(p->right) printPreOrder(p->right, indent+2);
}
}
template <class T>
void BST<T>::insert(T item, BSTNode<T> * & node){
if(!node){
node = new BSTNode<T>(item);
}
else if(item < node->data){
insert(item, node->left);
}
else{
insert(item, node->right);
}
balance(node);
}
template <class T>
void BST<T>::remove(BSTNode<T>*& temp){
if(temp->left == nullptr && temp->right == nullptr){
if(temp->parent == nullptr){
root = nullptr;
}
else if(temp->parent->left == temp){
temp->parent->left = nullptr;
}
else{
temp->parent->right = nullptr;
}
delete temp;
}
else if(temp->left == nullptr){ //promote right
BSTNode<T>* toDelete = temp->right;
temp->data = toDelete->data;
temp->left = toDelete->left;
temp->right = toDelete->right;
if(temp->left){
temp->left->parent = temp->left;
}
if(temp->right){
temp->right->parent = temp;
}
delete toDelete;
}
else if(temp->right == nullptr){ //promote left
BSTNode<T>* toDelete = temp->left;
temp->data = toDelete->data;
temp->left = toDelete->left;
temp->right = toDelete->right;
if(temp->left){
temp->left->parent = temp->left;
}
if(temp->right){
temp->right->parent = temp;
}
delete toDelete;
}
else{
BSTNode<T>* maxOfLeft = temp->left;
while(maxOfLeft){
maxOfLeft = maxOfLeft->right;
}
temp->data = maxOfLeft->data;
remove(maxOfLeft);
}
balance(temp);
}
template <class T>
void BST<T>::clear(BSTNode<T>*& root) {
if (root) {
if (root->left) {
clear(root->left);
}
if (root->right) {
clear(root->right);
}
delete root;
}
root = nullptr;
};
template <class T>
BST<T>::~BST(){
clear(root);
}
template <class T>
BST<T>* BST<T>::clone(BSTNode<T>* start){
if(!start){
return nullptr;
}
else{
return new BSTNode<T>(start->data, clone(start->left), clone(start->right));
}
}
template <class T>
BST<T>& BST<T>::operator=(const BST<T>& rhs){
if(this == &rhs){
return *this;
}
clear(root);
root = clone(rhs.root);
return *this;
}
template <class T>
void BST<T>::rotateRight(BSTNode<T> * & node){
BSTNode<T> * newParent = node->left;
node->left = newParent->right;
newParent->right = node;
node->height = max(height(node->right),height(node->left)) + 1;
newParent->height = max(height(newParent->left), node->height) + 1;
node = newParent; //set new root (we can't access newParent outside of this function!)
}
template <class T>
void BST<T>::rotateLeft(BSTNode<T> * & node){
BSTNode<T> * newParent = node->right;
node->right = newParent->left;
newParent->left = node;
node->height = max(height(node->right), height(node->left)) + 1;
newParent->height = max(height(newParent->right), node->height) + 1;
node = newParent; //set new root (we can't access newParent outside of this function!)
}
template <class T>
int BST<T>::height(BSTNode<T> *node){
if(node){
return node->height;
};
return -1;
}
template <class T>
void BST<T>::doubleRotateRight(BSTNode<T> * &node){
rotateLeft(node->left);
rotateRight(node);
}
template<class T>
void BST<T>::doubleRotateLeft(BSTNode<T> * &node){
rotateRight(node->right);
rotateLeft(node);
}
template<class T>
void BST<T>::balance(BSTNode<T> * &node){
if(!node){
return;
}
if(height(node->left) > height(node->right) + 1){
if(height(node->left->left) >= height(node->left->right)){
rotateRight(node);
}
else{
doubleRotateRight(node);
};
};
if(height(node->right) > height(node->left) + 1){
if(height(node->right->right) >= height(node->right->left)){
rotateLeft(node);
}
else{
doubleRotateLeft(node);
}
}
node->height = max(height(node->right), height(node->left)) + 1;
}
int main() {
vector<int>data = {5, 3, 4, 2, 1, 2, 6, 7};
BST<int> test;
for(int r : data){
test.insert(r, test.root);
}
test.printPreOrder(test.root,0);
cout << endl;
return 0;
}
Here is the output I am getting:
3
2
1
2
5
4
6
7
From my understanding, I should be getting the following output:
3
2
1
2
5
4
6
7
Don't use tabs.
Consider this example:
#include <iostream>
#include <iomanip>
int main() {
for (int indent=0;indent<5;++indent) {
if (indent) {
std::cout << std::setw(indent) << "\t" << "tabs" << "\n";
std::cout << std::setw(indent) << " " << "spaces" << "\n";
}
}
}
Possible output is:
tabs
spaces
tabs
spaces
tabs
spaces
tabs
spaces
I am having trouble getting past the initialization of the red black tree. Whenever I compile I get the following error.
redBlackTree.h:81:28: error: invalid conversion from ‘long int’ to ‘nodeColor’ [-fpermissive]
nodeType<myType> *x = new nodeType<myType>;
^
redBlackTree.h:10:8: error: invalid conversion from ‘long int’ to ‘nodeColor’ [-fpermissive]
struct nodeType
^
redBlackTree.h:81:28: note: synthesized method ‘nodeType<int>::nodeType()’ first required here
nodeType<myType> *x = new nodeType<myType>;
I am also having trouble searching the tree to make sure a value is not already inside the tree. The current method I can think of it this but I am still getting duplicate results inside of my tree.
if(nd != NULL)
{
if(nd->keyValue == x)
return true;
return ((search(x, nd->right)) || (search(x, nd->left)));
}
return false;
It is under the insertion function. Could it be how I am declaring my variables? We are supposed to follow a certain template and it says to make x a new nodeType but am not able to. Deleting it causes the program to have a seg fault.
#ifndef REDBLACKTREE_H
#define REDBLACKTREE_H
#include <iostream>
#include <sstream>
using namespace std;
enum nodeColor { RED, BLACK };
template<class myType>
struct nodeType
{
myType keyValue = keyValue;
nodeColor color = NULL;
nodeType *left = NULL;
nodeType *right = NULL;
nodeType *parent = NULL;
};
template <class myType>
class redBlackTree
{
public:
redBlackTree(){};
~redBlackTree();
void destroyTree();
unsigned int countNodes() const;
unsigned int height() const;
void printTree() const;
void insert(myType);
bool search(myType);
private:
nodeType<myType> *root = NULL;
bool search(myType, nodeType<myType> *);
void destroyTree(nodeType<myType> *);
unsigned int countNodes(nodeType<myType> *) const;
unsigned int height(nodeType<myType> *) const;
void printTree(nodeType<myType> *) const;
void rightRotate(nodeType<myType> *);
void leftRotate(nodeType<myType> *);
};
//template <class myType>
//redBlackTree<myType>::redBlackTree():root(NULL)
//{
//};
template <class myType>
redBlackTree<myType>::~redBlackTree()
{
destroyTree();
}
template <class myType>
void redBlackTree<myType>::destroyTree()
{
destroyTree(root);
};
template <class myType>
unsigned int redBlackTree<myType>::countNodes() const
{
return countNodes(root);
};
template <class myType>
unsigned int redBlackTree<myType>::height() const
{
return height(root);
};
template <class myType>
void redBlackTree<myType>::printTree() const
{
printTree(root);
};
template <class myType>
void redBlackTree<myType>::insert(myType value)
{
if(search(value))
return;
nodeType<myType> *x = new nodeType<myType>;
x->right = NULL;
x->left = NULL;
x->parent = NULL;
x->keyValue = value;
x->color = RED;
if(root == NULL)
{
root = x;
x->color = BLACK;
return;
}
nodeType<myType> *curr = root;
if(curr->keyValue > x->keyValue)
{
curr->left = x;
x->parent = curr;
x->color = RED;
}
else
{
curr->right = x;
x->parent = curr;
x->color = RED;
}
while(x != root && x->parent->color == RED)
{
if(x->parent == x->parent->parent->left)
{
if(x->parent->parent->right != NULL && x->parent->parent->color == RED)
{
x->parent->color = BLACK;
x->parent->parent->right->color = BLACK;
x->parent->parent->color = RED;
x = x->parent->parent;
}
else
{
if(x == x->parent->right)
{
x = x->parent;
leftRotate(x);
}
x->parent->color = BLACK;
x->parent->parent->color = RED;
rightRotate(x->parent->parent);
}
}
else
{
if(x->parent->parent->left != NULL && x->parent->parent->color == RED)
{
x->parent->color = BLACK;
x->parent->parent->left->color = BLACK;
x->parent->parent->color = RED;
x = x->parent->parent;
}
else
{
if(x == x->parent->right)
{
x = x->parent;
rightRotate(x);
}
x->parent->color = BLACK;
x->parent->parent->color = RED;
leftRotate(x->parent->parent);
}
}
if(x == root)
x->color = BLACK;
}
};
template <class myType>
bool redBlackTree<myType>::search(myType x)
{
search(x, root);
};
template <class myType>
bool redBlackTree<myType>::search(myType x, nodeType<myType> *nd)
{
if(nd == NULL)
return 0;
search(x, nd->left);
search(x, nd->right);
if(nd->keyValue == x)
return true;
else
return false;
};
template <class myType>
void redBlackTree<myType>::destroyTree(nodeType<myType> *node)
{
if(node==NULL)
return;
destroyTree(node->left);
destroyTree(node->right);
delete node;
};
template <class myType>
unsigned int redBlackTree<myType>::countNodes(nodeType<myType> *nd) const
{
if(nd==NULL)
return 0;
return (countNodes(nd->left) + countNodes(nd->right) + 1);
};
template <class myType>
unsigned int redBlackTree<myType>::height(nodeType<myType> *nd) const
{
int leftHeight = 0;
int rightHeight = 0;
if(nd==NULL)
return 1;
leftHeight = leftHeight + height(nd->left);
rightHeight = rightHeight + height(nd->right);
if(leftHeight == rightHeight)
return leftHeight;
else if(leftHeight > rightHeight)
return leftHeight;
else
return rightHeight;
};
template <class myType>
void redBlackTree<myType>::printTree(nodeType<myType> *nd) const
{
if(nd == NULL)
return;
printTree(nd->left);
cout << nd->keyValue;
printTree(nd->right);
cout << nd->keyValue;
};
template <class myType>
void redBlackTree<myType>::rightRotate(nodeType<myType> *y)
{
nodeType<myType> *x = y->left;
x->left = x->right;
if(x->right != NULL)
x->right->parent = y;
x->parent = y->parent;
if(x->parent == NULL)
root = x;
else if(y == y->parent->left)
y->parent->left = x;
else
y->parent->right = x;
x->right = y;
y->parent = x;
};
template <class myType>
void redBlackTree<myType>::leftRotate(nodeType<myType> *x)
{
nodeType<myType> *y = y->right;
x->right = y->left;
if(x->right != NULL)
root = y;
else if(x == x->parent->left)
x->parent->left = y;
else
x->parent->right = y;
x->left = x;
x->parent = y;
};
#endif
The problem is caused by the line:
nodeColor color = NULL;
NULL is not a valid value for color. Use a value that is valid, such as:
nodeColor color = RED;
Also, the line
myType keyValue = keyValue;
is going to be a problem. It initializes keyValue with the uninitialized value of keyValue.Make the RHS of that line something more appropriate, such as:
myType keyValue = {};
You are missing a return in the first search function.
template <class myType>
bool redBlackTree<myType>::search(myType x)
{
return search(x, root);
// ^^
}
You don't need ; at the end of member function definition. You have them in some of the function definitions. You should remove them.
this is my current avltree implementation, avltree.h:
#pragma once
#include <math.h>
#include <algorithm>
#include <iostream>
namespace avltree {
template <class T>
struct node {
static node * null_node;
node *left = null_node;
node *right = null_node;
node *parent = null_node;
int height = 0;
T value;
node(T value) :value(value) {}
node(T value, int height) :height(height), value(value) {}
};
template <class T>
node<T>* node<T>::null_node = new node(0, -1);
template <class T>
struct avltree {
public:
node<T> *root;
avltree(T value);
node<T> *insert(T value);
void print(void);
void print_with_height(void);
private:
node<T> *insert(T value, node<T> *x);
node<T> *left_rotate(node<T> *x);
node<T> *right_rotate(node<T> *x);
void retrace(node<T> *n);
void update_root();
void print(node<T> *n);
void print(node<T> *n, int depth);
void update_height(node<T> *n);
};
template <class T>
avltree<T>::avltree(T value) :root(new node<T>(value)) { }
template <class T>
node<T> *avltree<T>::insert(T value) {
auto n = insert(value, root);
update_root();
return n;
}
template <class T>
void avltree<T>::retrace(node<T> *n) {
while (n != node<T>::null_node) {
update_height(n);
if (n->left->height - n->right->height > 1) {
if (n->left->left->height >= n->left->right->height) {
right_rotate(n);
}
else {
left_rotate(n);
right_rotate(n);
}
}
else
if (n->right->height - n->left->height > 1) {
if (n->right->right->height >= n->right->left->height) {
left_rotate(n);
}
else {
right_rotate(n);
left_rotate(n);
}
}
n = n->parent;
}
}
template <class T>
node<T> *avltree<T>::insert(T value, node<T> *n) {
if (n->value > value) {
if (n->left != node<T>::null_node) {
n->left->height++;
insert(value, n->left);
}
else {
auto new_node = new node<T>(value);
n->left = new_node;
new_node->parent = n;
retrace(n);
return new_node;
}
}
if (n->value < value) {
if (n->right != node<T>::null_node) {
n->right->height++;
insert(value, n->right);
}
else {
auto new_node = new node<T>(value);
n->right = new_node;
new_node->parent = n;
retrace(n);
return new_node;
}
}
update_height(n);
return n;
}
template <class T>
node<T> *avltree<T>::left_rotate(node<T> *x) {
node<T> *y = x->right;
if (y == node<T>::null_node) {
return node<T>::null_node;
}
y->parent = x->parent;
if (x->parent->right == x) {
x->parent->right = y;
}
else {
x->parent->left = y;
}
y->left = x;
x->parent = y;
x->right = y->left;
x->right->parent = x;
update_height(x);
update_height(y);
return x;
}
template <class T>
node<T> *avltree<T>::right_rotate(node<T> *x) {
node<T> *y = x->left;
if (y == node<T>::null_node) {
return node<T>::null_node;
}
y->parent = x->parent;
if (x->parent->right == x) {
x->parent->right = y;
}
else {
x->parent->left = y;
}
y->right = x;
x->parent = y;
x->left = y->right;
x->left->parent = x;
update_height(x);
update_height(y);
return x;
}
template <class T>
void avltree<T>::update_root() {
auto n = root, last = root;
while (n != node<T>::null_node) {
last = n;
n = n->parent;
}
root = last;
}
template <class T>
void avltree<T>::print(void) {
print(root);
cout << endl;
}
template <class T>
void avltree<T>::print(node<T> *n) {
if (n->left != node<T>::null_node) {
print(n->left);
}
cout << n->value << " ";
if (n->right != node<T>::null_node) {
print(n->right);
}
}
template <class T>
void avltree<T>::print(node<T> *n, int height) {
if (n->left != node<T>::null_node) {
print(n->left, height);
}
if (n->height == height) {
std::cout << n->value << ", ";
}
if (n->right != node<T>::null_node) {
print(n->right, height);
}
}
template <class T>
void avltree<T>::print_with_height(void) {
int height = root->height;
for (int height = root->height; height >= 0; height--) {
std::cout << "height = " << height << "\t:";
print(root, height);
std::cout << std::endl;
}
std::cout << std::endl;
}
template <class T>
void avltree<T>::update_height(node<T> *n) {
n->height = std::max(n->left->height, n->right->height) + 1;
}
}
And the following is main file:
#include "stdafx.h"
#include "avltree.h"
int main()
{
avltree::avltree<int> tree(1);
for (int i = 2; i < 128; i++) {
tree.insert(i);
}
tree.print_with_height();
return 0;
}
The problem with above code is that at iteration 124 it will generate an infinite loop inside retrace call in insert. Basically, the nodes will keep being rotated in such a way that root node cannot be reached (resulting in an infinite loop). I have checked the trivial examples (for a few nodes) and they work. Everything for a run is provided, I would appreciate if someone with experience in avltrees could take their time and run this program, perhaps finding out what goes wrong inside retrace/rotations.
Getting an infinite loop like that indicates a likely problem with your rotate functions. A quick look at left_rotate shows
y->left = x;
x->parent = y;
x->right = y->left;
What is y->left in that last assignment? x, so what you're really is x->right = x. This is clearly a problem that needs to be fixed.
A similar problem exists in right_rotate.
I am trying to finish a C++ project where I have to insert an array of integers into a binary search tree. I have to use a particular insertion algorithm:
insert(T, z)
1 y = NIL
2 x = T.root
3 while x != NIL
4 y = x
5 if z.key < x.key
6 x = x.left
7 else x = x.right
8 z.p = y
9 if y == NIL
10 T.root = z
11 else if z.key < y.key
12 y.left = z
13 else y.right = z
Here is my code so far:
main.cpp
#include <iostream>
#include "binarytree.h"
using namespace std;
int main()
{
BinaryTree tree;
int array [10] = {30, 10, 45, 38, 20, 50, 25, 33, 8, 12};
for (int i = 0; i < 10; i++)
{
tree.add(array[i]);
}
tree.inordertreewalk();
return 0;
}
void BinaryTree::insert(node *&T, node *&z)
{
node *y = nullptr;
y = new node;
y->key = 0;
y->left = y->right = y->parent = nullptr;
node *x = T;
while (x != nullptr)
{
y = x;
if (z->key < x->key)
x = x->left;
else
x = x->right;
}
z->parent = y;
if (y == nullptr)
T = z;
else if (z->key < y->key)
y->left = z;
else
y->right = z;
}
void BinaryTree::add(int num)
{
node *newNode = nullptr;
newNode = new node;
newNode->left = newNode->right = newNode->parent = nullptr;
newNode->key=num;
insert(root, newNode);
}
void BinaryTree::inordertreewalk(node *x) const
{
if (x)
{
inordertreewalk(x->left);
cout << x->key << endl;
inordertreewalk(x->right);
}
}
void BinaryTree::destroysubtree(node *newNode)
{
if (newNode)
{
if (newNode->left)
destroysubtree(newNode->left);
if (newNode->right)
destroysubtree(newNode->right);
delete newNode;
}
}
binarytree.h
#ifndef BINARYTREE_H_
#define BINARYTREE_H_
#include <iostream>
using namespace std;
class BinaryTree
{
private:
struct node
{
int key;
node* left;
node* right;
node* parent;
};
node *root;
void insert(node *&, node *&);
void inordertreewalk(node *) const;
void destroysubtree(node *);
public:
BinaryTree()
{ root = nullptr; }
~BinaryTree()
{ destroysubtree(root); }
void add(int);
void inordertreewalk() const
{ inordertreewalk(root); }
};
#endif
This program compiles, however it is not displaying the tree. I know that the problem is with my implementation of the insertion algorithm because I used a different algorithm I found in a textbook and kept the rest of the code the same and the tree was displayed in order. I know that T is a pointer to the root, but I'm not sure if the numbers are being correctly stored in the tree.
Thanks for your help.