I'm coding the Red-Black-Tree by following Introduction to Algorithms. And when it comes to the right-rotate function, one of my pointer was modified unexpectedly.
void RBTree::RightRotate(pNode &z)
{
pNode l=z->lChild;
z->lChild = l->rChild; //link z->l-r to z as a lChild
if(l->rChild != nil)
l->rChild->p = z;
l->p = z->p; //when pass the tree's root as parameter
//z,after executing this line, z was
//modified to pointing to nil
//(known from debug window), why?
if(z->p == nil)
root = l;
else if (z == z->p->lChild)
z->p->lChild = l;
else
z->p->rChild = l;
l->rChild=z;
z->p=l;
}
And just as Introduction to Algorithms goes, I set nil pointer in my class.
Since only when root was passed as parameter z can cause this problem, I defer it's something wrong with nil and root.The following is the whole code.
:
#include
#include
#include
#define RED 1
#define BLACK 0
using namespace std;
typedef struct Node
{
int color, val;
struct Node* lChild, *rChild, *p;
Node(int val_, struct Node* tmp)
{color=RED, val=val_,lChild=rChild=p=tmp;}
Node(){color=BLACK, val=0,lChild=rChild=p=NULL;}
}Node,*pNode;
class RBTree
{
public:
RBTree()
{
root=NULL;
}
~RBTree()
{
Free_(root);
}
void Free_(pNode p)
{
if(p!=NULL)
{
Free_(p->lChild);
Free_(p->rChild);
delete(p);
p=NULL;
}
}
pNode FindMin() const
{
pNode p=root;
if (p)
while(p->lChild)
p=p->lChild;
return p;
}
pNode FindMax() const
{
pNode p=root;
if (p)
while(p->rChild)
p=p->rChild;
return p;
}
void Print(pNode p, int n) const
{
if(!p)
return;
Print(p->rChild,n+2);
for(int i=0;ivalcolor==1)?"R":"B")lChild,n+2);
}
pNode Root() {return root;}
void Insert(int const& val_);
void InsertFixup(pNode &z);
void LeftRotate(pNode &p);
void RightRotate(pNode &p);
pNode Search(pNode const &p, int x) const;
void Delete(pNode &p, int x);
private:
pNode root;
static pNode nil;
};
pNode RBTree::nil = new Node();
/*
Inserting pipiline:
Insert node into RBTree, then fixup.
In the fixup procedure , rotate may be called
*/
void RBTree::InsertFixup(pNode &z)
{
while (z->p->color == RED)
{
pNode y;
if (z->p == z->p->p->lChild)
{
y=z->p->p->rChild;
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->rChild)
{
z = z->p;
LeftRotate(z);
}
z->p->color = BLACK;
z->p->p->color = RED;
RightRotate(z->p->p);
}
}
else
{
y=z->p->p->lChild;
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->lChild)
{
z = z->p;
RightRotate(z);
}
z->p->color = BLACK;
z->p->p->color = RED;
LeftRotate(z->p->p);
}
}
}
root->color = BLACK;
}
void RBTree::Insert(int const &val_)
{
pNode z=new Node(val_, nil); //set val, lChild, rChild, p to NULL, color to RED
pNode x = root;
pNode pre = nil;
if(NULL == root)
root = z;
else
{
while (x!=nil)
{
pre=x;
x=(x->valrChild:x->lChild;
}
z->p = pre;
if (z->val val)
pre->lChild = z;
else
pre->rChild = z;
}
InsertFixup(z);
}
//left-rotate
//denote z, z's rChild == r
//parent changed: z, r, r's lChild
//child chagend: z->rChild, r->lChild, z->p->lChild/rChild
void RBTree::LeftRotate(pNode &z)
{
pNode r=z->rChild;
z->rChild = r->lChild; //link p->r-l to p as a r
if(r->lChild != nil)
r->lChild->p = z;
r->p = z->p;
if(z->p == nil)
root = r;
else if (z == z->p->lChild)
z->p->lChild = r;
else
z->p->rChild = r;
r->lChild=z;
z->p=r;
}
// right-rotate
void RBTree::RightRotate(pNode &z)
{
pNode l=z->lChild;
z->lChild = l->rChild; //link p->l-r to p as a l
if(l->rChild != nil)
l->rChild->p = z;
l->p = z->p;
if(z->p == nil) //link parent from top to bottom
root = l;
else if (z == z->p->lChild)
z->p->lChild = l;
else
z->p->rChild = l;
l->rChild=z;
z->p=l;
}
int main()
{
int a[9] = {11, 2, 14, 1, 7, 15, 5, 8, 4};
RBTree tr;
for(int i=0;i
Am I using nil in a wrong way?
Thanks.
Nill is not a C++ expression. However some environments might include it, just using it as an alias for NULL or 0. If you use C++11, I would recommend nullptr
Try to have a look whether
l->p < z && z< l->p + sizeof(z)
If that is the case, you are assigning to z.
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 had found this implementation in [github][1], i made some changes like adding a 2nd value to the node, and using each left and right node as a pointer Node the problem with the tree it is and whenever inserting nodes then searching in the nodes in the tree it only iterates through the tree from first to last pointers when using TMapFind which calls the function pointer TMapNodeComparison_F to compare pointers. I wonder what could be causing this bug I suspect it's something in the logic of TMapInsertNode checking if a node is black/red?
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <sstream>
#define ASSERT_NOT_NULL(x) if(x)
#define ASSERT_NULL(x) if(x ==NULL)
#define ASSERT_NULL_(x,y) if(x== NULL && y==NULL)
typedef struct CByte
{
unsigned char* value;
size_t index;
size_t length;
}BYTES;
//struct Data;
struct Node;
struct TMap;
struct Node
{
CByte* value;
size_t index;
struct Node* Left;
struct Node* Right;
struct Node* Parent;
bool color;
};
typedef int (*TMapNodeComparison_F) (struct TMap* map, struct Node* a, struct Node* b);
typedef void (*TMapNode_F) (struct TMap* map, struct Node* node);
struct TMap
{
struct Node* root;
size_t TSize;
TMapNodeComparison_F compareNodeFunction;
};
struct Node* TMapNodeAlloc()
{
return (Node*)malloc(sizeof(Node));
}
struct Node* TMapNodeCalloc()
{
return (Node*)calloc(1,sizeof(Node));
}
struct Node* TMapInitializationNodeTree(struct Node* node,struct CByte* _data)
{
ASSERT_NOT_NULL (node)
{
node->value = _data;
std::string s = reinterpret_cast<char const*>(_data->value);
std::cout << s << std::endl;
node->color = 1;//Initialize as Black
node->Left = node->Right = NULL;
node->index = _data->index;
}
return node;
}
struct Node* TMapInitializationCreateNode(CByte* _data)
{
return TMapInitializationNodeTree(TMapNodeAlloc(), _data);
}
void TMapNodeDeAlloc(struct Node* node)
{
ASSERT_NOT_NULL(node)
free(node);
}
int AreNodesRed(struct Node* nodeA, struct Node* nodeB)
{
return (nodeA && nodeB) ? !nodeA->color && !nodeB->color : 0;
}
static bool TMapIsNodeBlack (struct Node* node)
{
return node ? node->color == 1 : false;
}
static bool TMapIsNodeRed(struct Node* node)
{
return node ? !node->color : false;
}
static bool TMapAreNodesBlack(struct Node* nodeA,struct Node* nodeB)
{
return nodeA && nodeB ? nodeA->color == 1 && nodeB->color ==1 : false;
}
static struct Node* TMapNodeRotateL(struct TMap* map,struct Node* node , int side)
{
struct Node* blackNode = NULL;
ASSERT_NOT_NULL (node)
{
blackNode = !side == 0 ? node->Left : node->Right;
/* blackNode->Left = blackNode->Right = (Node*)calloc(1, sizeof(Node));*/
!side == 0 ? node->Left : node->Right = side == 0 ? blackNode->Left : blackNode->Right;
node->color = 0; //Red
blackNode->color = 1;//Black
side == 0 ? blackNode->Left : blackNode->Right = node;
node->Parent = blackNode;
}
return blackNode;
}
static struct Node* TMapNodeRotateR(TMap* map,struct Node* node,int side)
{
struct Node* rightNode = NULL;
ASSERT_NULL(node)
{
!side ==0 ? node->Left :node->Right = TMapNodeRotateL(map,!side == 0 ? node->Left : node->Right,!side);
rightNode = TMapNodeRotateL(map,node,side);
}
return rightNode;
}
int TMapNodeComparison(struct TMap* map, struct Node* a, struct Node* b)
{
return (a->value > b->value) - (a->value < b->value);
}
void TMapNodeDealloc(struct TMap* map, struct Node* node)
{
ASSERT_NOT_NULL (map)
{
ASSERT_NOT_NULL (node)
{
TMapNodeDeAlloc(node);
}
}
}
struct TMap* TMapAlloc()
{
return (TMap*)malloc(sizeof(TMap));
}
struct TMap* TMapInitialize(struct TMap* map, TMapNodeComparison_F node_cmp_cb)
{
ASSERT_NOT_NULL (map)
{
map->root = NULL;
map->TSize = 0;
map->compareNodeFunction = node_cmp_cb ? node_cmp_cb : TMapNodeComparison;
}
return map;
}
struct TMap* TMapCreate(TMapNodeComparison_F node_cb)
{
return TMapInitialize(TMapAlloc(), node_cb);
}
void TMapDealloc(struct TMap* map, TMapNode_F node_cb)
{
ASSERT_NOT_NULL(map)
{
ASSERT_NOT_NULL(node_cb)
{
struct Node* node = map->root;
struct Node* save = NULL;
while (node)
{
ASSERT_NULL (node->Left)
{
save = node->Right;
node_cb(map, node);
node = NULL;
}
else
{
save = node->Left;
node->Left = save->Right;
save->Right = node;
}
node = save;
}
}
free(map);
}
}
int
rb_tree_test(struct TMap* map, struct Node* root)
{
int lh, rh;
if (root == NULL)
return 1;
else
{
struct Node* ln = root->Left;
struct Node* rn = root->Right;
/* Consecutive red links */
if (TMapIsNodeRed(root))
{
if (AreNodesRed(ln,rn))
{
printf("Red violation");
return 0;
}
}
lh = rb_tree_test(map, ln);
rh = rb_tree_test(map, rn);
/* Invalid binary search tree */
if
((ln != NULL && map->compareNodeFunction(map, ln, root) >= 0)
|| (rn != NULL && map->compareNodeFunction(map, rn, root) <= 0))
{
puts("Binary tree violation");
return 0;
}
/* Black height mismatch */
if (lh != 0 && rh != 0 && lh != rh)
{
puts("Black violation");
return 0;
}
/* Only count black links */
if (lh != 0 && rh != 0)
return TMapIsNodeRed(root) ? lh : lh + 1;
else
return 0;
}
}
void* TMapFind(struct TMap* map, CByte* value)
{
void* result = NULL;
ASSERT_NOT_NULL (map)
{
struct Node node;
node.value = value;
struct Node* it = map->root;
int cmp = 0;
while (it)
{
if ((cmp = map->compareNodeFunction(map, it, &node)))
{
it = cmp < 0 ? it->Right : it->Left;
}
else
break;
}
result = it ? it->value : NULL;
}
return result;
}
#define CompareANullElement(nonNull,Null) ((!Null || !nonNull) ? (0) : nonNull==Null)
int TMapInsertNode(struct TMap* self, struct Node* node)
{
int result = 0;
if (self && node)
{
ASSERT_NULL (self->root)
{
self->root = node;
result = 1;
}
else
{
struct Node head = { NULL };
struct Node* g, * t;
struct Node* p, * q;
int dir = 0, last = 0;
// Set up our helpers
t = &head;
g = p = NULL;
q = t->Right = self->root;
while (1)
{
ASSERT_NULL (q)
{
// Insert node at the first null link.
p->Left = q = node;
}
else if (AreNodesRed(q->Left,q->Right))
{
q->color = 0;//red
q->Left->color = 1;// black
q->Right->color = 1;// black
}
if (AreNodesRed(q,p))
{
int dir2 = CompareANullElement(t->Right,g);
if (CompareANullElement(q,(last == 0 ? p->Left : p->Right)))
{
t->Right = TMapNodeRotateL(self,g,!last);
}
else
{
t->Left = TMapNodeRotateR(self,g,!last);
}
}
// Stop working if we inserted a node. This
// check also disallows duplicates in the tree
if (self->compareNodeFunction(self, q, node) == 0)
{
break;
}
last = dir;
dir = self->compareNodeFunction(self, q, node) < 0;
// Move the helpers down
if (g != NULL)
{
t = g;
}
g = p, p = q;
q = dir ==0 ? q->Left : q->Right;
}
// Update the root (it may be different)
self->root = head.Right;
}
// Make the root black for simplified logic
self->root->color = 1;
++self->TSize;
}
return 1;
}
int TMapInsert(struct TMap* map, CByte* value)
{
return TMapInsertNode(map, TMapInitializationCreateNode(value));
}
int TMapRemoveFrom(struct TMap* map, CByte* value, TMapNode_F node_cb)
{
ASSERT_NOT_NULL (map->root)
{
struct Node head = { 0 };
struct Node node;
node.value = value ;
struct Node* q, * p, * g;
struct Node* f = NULL;
int dir = 1;
q = &head;
g = p = NULL;
q->Right = map->root;
while ((dir == 0 ? q->Left : q->Right) != NULL)
{
int last = dir;
g = p, p = q;
q = dir == 0 ? q->Left : q->Right;
dir = map->compareNodeFunction(map, q, &node) < 0;
if (map->compareNodeFunction(map, q, &node) == 0)
{
f = q;
}
// Push the red node down with rotations and color flips
if (TMapIsNodeBlack(q) && TMapIsNodeBlack(dir == 0 ? q->Left : q->Right))
{
if (TMapIsNodeRed(!dir == 0 ? q->Left : q->Right))
{
p = last == 0 ? p->Left : p->Right = TMapNodeRotateL(map,q,dir);
}
else if (TMapIsNodeBlack(!dir == 0 ? q->Left : q->Right))
{
struct Node* s = !last == 0 ? p->Left : p->Right;
if (s)
{
if (TMapAreNodesBlack(!last == 0 ? s->Left : s->Right,last == 0 ? s->Left : s->Right))
{
// Color flip
p->color = 1;
s->color = 0;
q->color = 0;
}
else
{
int dir2 = g->Right == p;
if (TMapIsNodeRed(last == 0 ? s->Left : s->Right)) //check for red
{
dir2 == 0 ? s->Left : s->Right = TMapNodeRotateR(map,p,last);
}
else if (TMapIsNodeBlack((last != 0 ? s->Left : s->Right)))
{
dir2 == 0 ? g->Left: g->Right = TMapNodeRotateL(map,p,last);
}
// Ensure correct coloring
q->color = dir2 == 0 ? g->Left->color : g->Right->color = 0;
dir2==0 ? g->Left->Left->color : g->Right->Left->color = 1;
dir2 == 0 ? g->Left->Right->color : g->Right->Right->color = 1;
}
}
}
}
}
// Replace and remove the saved node
ASSERT_NOT_NULL (f)
{
CByte* tmp = f->value;
f->value = q->value;
q->value = tmp;
p->Right == q ? p->Right : p->Left = ((q->Left == NULL) ? q->Right: q->Left);
ASSERT_NOT_NULL (node_cb)
{
node_cb(map, q);
}
q = NULL;
}
// Update the root (it may be different)
map->root = head.Right;
// Make the root black for simplified logic
if (map->root != NULL)
{
map->root->color = 1;
}
--map->TSize;
}
return 1;
}
int TMapRemoveTree(struct TMap* map, CByte* value)
{
int result = 0;
ASSERT_NOT_NULL (map)
{
result = TMapRemoveFrom(map, value, TMapNodeDealloc);
}
return result;
}
size_t TMapGetSize(struct TMap* map)
{
size_t result = 0;
ASSERT_NOT_NULL(map)
{
result = map->TSize;
}
return result;
}
int my_cmp_cb(struct TMap* self, struct Node* node_a, struct Node* node_b)
{
BYTES* a = (BYTES*) node_a->value;
BYTES* b = (BYTES*) node_b->value;
return (a->value > b->value) - (a->value < b->value);
}
int main()
{
int t = true;
int d,c = 1;
(t ? d : c) = 2;
struct TMap* tree = TMapCreate(my_cmp_cb);
std::cout << sizeof(*tree) << std::endl;
ASSERT_NOT_NULL (tree)
{
BYTES* bytes = (BYTES*)calloc(1000,sizeof(BYTES));
std::stringstream ss;
// Use the tree here...
for (int i = 0; i < 1000; i++)
{
// Default insert, which allocates internal rb_nodes for you.
ss << i;
auto message = std::string("Hello " + ss.str());
unsigned char* val = new unsigned char[message.length() + 1];
strcpy((char*)val, message.c_str());
bytes[i].value = val;
bytes[i].index = i;
bytes[i].length = sizeof(message) / sizeof(unsigned char*);
TMapInsert(tree, &bytes[i]);
ss.str("");
ss.clear();
}
std::string str ="Hello 2";
BYTES b { (unsigned char*)str.c_str(), 2, 8 };
// To f
BYTES* f = (BYTES*)TMapFind(tree, &b);
if (f)
{
fprintf(stdout, "found BYTES(value = %s, index = %ull, length = %ull )\n", f->value,f->index,f->length);
}
else {
printf("not found\n");
}
TMapDealloc(tree, NULL);
}
}
[1]: https://github.com/mirek/rb_tree/blob/master/rb_tree.c
I'm trying to overload [] for red-black tree. Each node contains four elements: key, gender, height and weight. "key" value will be randomly assigned and should be unique, so I want to overload [] by traversing each node to see if the "key" value already exists. However, it worked only when there was just one node. Here's the code:
#include<iostream>
#include<string>
using namespace std;
enum COLOR { RED, BLACK };
class Node
{
public:
Node(int key, string gender, int height, int weight, const COLOR & color = RED)
:pLeft(NULL), pRight(NULL), pParent(NULL), key(key), gender(gender), height(height), weight(weight), color(color)
{}
~Node();
string getGender();
int getHeight();
int getWeight();
Node* pLeft;
Node* pRight;
Node* pParent;
int key;
string gender;
int height;
int weight;
COLOR color;
};
class RBTree
{
public:
RBTree() :pRoot(NULL) {}
Node &operator[](int key);
bool insert(int key, string gender, int height, int weight);
void RotateL(Node* parent);
void RotateR(Node* parent);
void InOrder();
void InOrder(Node* pRoot);
Node* searchTree(Node* pRoot, int key);
bool CheckRBTree();
bool CheckRBTree(Node* pRoot,int counter,int k);
private:
Node* pRoot;
};
string Node::getGender()
{
return gender;
}
int Node::getHeight()
{
return height;
}
int Node::getWeight()
{
return weight;
}
Node &RBTree::operator[](int key)
{
Node* ptr = searchTree(pRoot, key);
return *ptr;
}
bool RBTree::insert(int key, string gender, int height, int weight)
{
// create root
if (pRoot == NULL)
{
pRoot = new Node(key, gender, height, weight);
pRoot->color = BLACK;
return true;
}
// find loc to insert
Node* pCur = pRoot;
Node* parent = NULL;
while (pCur)
{
if (key < pCur->key)
{
parent = pCur;
pCur = pCur->pLeft;
}
else if (key > pCur->key)
{
parent = pCur;
pCur = pCur->pRight;
}
else
return false;
}
// insert
pCur = new Node(key, gender, height, weight);
if (key < parent->key)
parent->pLeft = pCur;
else
parent->pRight = pCur;
pCur->pParent = parent;
// discuss 3 cases
while (pRoot != pCur&&pCur->pParent->color == RED)
{
Node* gf = parent->pParent;
if (gf->pLeft == parent)
{
Node* uncle = gf->pRight;
if (uncle&&uncle->color == RED)
{
parent->color = BLACK;
uncle->color = BLACK;
gf->color = RED;
pCur = gf;
parent = pCur->pParent;
}
else // turn case 3 into case 2
{
if (parent->pRight == pCur)
{
RotateL(parent);
std::swap(parent, pCur);
}
gf->color = RED;
parent->color = BLACK;
RotateR(gf);
}
}
else
{
Node*uncle = gf->pLeft;
if (uncle && uncle->color == RED) //case 1
{
parent->color = BLACK;
uncle->color = BLACK;
gf->color = RED;
pCur = gf;
parent = pCur->pParent;
}
else // turn case 3 into case 2
{
if (parent->pLeft == pCur)
{
RotateR(parent);
std::swap(parent, pCur);
}
gf->color = RED;
parent->color = BLACK;
RotateL(gf);
}
}
}
pRoot->color = BLACK;
return true;
}
// rotate left
void RBTree::RotateL(Node* parent)
{
Node* subR = parent->pRight;
Node* subRL = subR->pLeft;
parent->pRight = subRL;
if (subRL)
subRL->pParent = parent;
subR->pLeft = parent;
Node* gparent = parent->pParent;
parent->pParent = subR;
subR->pParent = gparent;
if (gparent == NULL)
pRoot = subR;
else if (gparent->pLeft == parent)
gparent->pLeft = subR;
else
gparent->pRight = subR;
}
void RBTree::RotateR(Node* parent)
{
Node* subL = parent->pLeft;
Node* subLR = subL->pRight;
parent->pLeft = subLR;
if (subLR)
subLR->pParent = parent;
subL->pRight = parent;
Node* gparent = parent->pParent;
parent->pParent = subL;
subL->pParent = gparent;
if (gparent == NULL)
pRoot = subL;
else if (gparent->pLeft == parent)
gparent->pLeft = subL;
else
gparent->pRight = subL;
}
void RBTree::InOrder()
{
cout << "InOrder: ";
InOrder(pRoot);
cout << endl;
}
void RBTree::InOrder(Node* pRoot)
{
if (pRoot)
{
InOrder(pRoot->pLeft);
cout << pRoot->key << " ";
InOrder(pRoot->pRight);
}
}
Node* RBTree::searchTree(Node* pRoot, int key)
{
if(pRoot->key == key)
return pRoot;
if(pRoot)
{
cout << "current node is " << pRoot->key << endl;
searchTree(pRoot->pLeft, key);
searchTree(pRoot->pRight, key);
}
return NULL;
}
bool RBTree::CheckRBTree()
{
if (pRoot == NULL)
return true;
if (pRoot->color == RED)
return false;
int blackcount = 0;
Node* pCur = pRoot;
while (pCur)
{
if (pCur->color == BLACK)
blackcount++;
pCur = pCur->pLeft;
}
return CheckRBTree(pRoot, blackcount, 0);
}
bool RBTree::CheckRBTree(Node* pRoot, int counter, int k)
{
if (pRoot == NULL)
return true;
if (pRoot->color == BLACK)
k++;
Node* parent = pRoot->pParent;
if (parent && parent->color == RED && pRoot->color == RED)
return false;
if (pRoot == NULL)
{
if (k != counter)
return false;
}
return CheckRBTree(pRoot->pLeft, counter, k)
&& CheckRBTree(pRoot->pRight, counter, k);
}
int main()
{
int a[] = { 10, 7, 8, 15, 5, 6, 11, 13, 12 };
RBTree t;
for (int index = 0; index < sizeof(a) / sizeof(a[0]); index++)
{
cout << a[index] << " ";
t.insert(a[index], "male", 12, 3);
}
cout << endl;
cout << t[7].getGender() << endl;
return 0;
}
Anyone knows how to fix this? Thanks in advance.
You didn't implement searchTree yet it seems.
Node* RBTree::searchTree(Node* pRoot, int key)
{
if(pRoot->key == key)
return pRoot;
if(pRoot)
{
cout << "current node is " << pRoot->key << endl;
searchTree(pRoot->pLeft, key);
searchTree(pRoot->pRight, key);
}
return NULL;
}
You return the root if it matches and all other cases return NULL. That can't work.
Note: You use pRoot->key and only after that check if(pRoot). If pRoot is NULL you already crashed there.
I have been staring at this all day and have gotten slightly somewhere, but it's still not working correctly! Just trying to 'put' (really insert, or find if it's there) an element k into a LL red black tree. Here's my method:
Node * RPut(Node* p, const K& k, Node*& location)
{
// if you are at the bottom of the tree,
// add new node at bottom of the tree
if (p == 0)
{
// new red note with new data
location = NewNode(k, Data(), RED);
return location;
}
if(greater_(k,p->key_))
{
// if it's greater than the root, move down to the left child
p->left_ = Rput(p->left_, k, location);
}
// right subtree
else if (greater_(p->key_,k))
{
// but if the key is less than root, move down to right child
p->right_ = Rput(p->right_, k, location);
}
// if they are equal
else
{
location = p;
}
// code for rotating
// this sort of worked.
if(p->right_ && p->right_->IsRed())
{
p = RotateLeft(p);
if (p->left_->IsBlack())
{
p->SetBlack();
p->left_->SetRed();
}
}
if (p->left_ && p->left_->IsRed())
{ if (p->left_->left_ && p->left_->left_->IsRed())
{
p = RotateRight(p);
p->left_->SetBlack();
p->right_->SetBlack();
}
}
return p;
}
I know my rotate methods work perfectly. This inserts correctly until the fifth element (I haven't tried every combination, but usually.) For instance, abcde inserted correctly would be
d
b e
a c --
[with b as red node]
mine works but stops here, giving me:
b
a d
- - c e
with NO red nodes.
Anyone see anything obvious I am overlooking or why it isn't working properly? Any help at all much appreciated.
Thanks!
This does not directly answer the question, but have you read Sedgewick's paper on left-leaning red black trees? The code in it is exceptionally clear, there are beautiful diagrams explaining how things work, and, I imagine, it would be straight-forward to reimplement everything into C++.
Edit
I tried, for fun to implement Sedgewick's code. It turns out the paper had a few methods/subroutines left out that would have been pretty helpful to include. Anyway, my C++11 implementation, along with some tests, follows.
Since Java does automagic memory management, Sedgewick doesn't explicitly note where memory should be freed in his code. Rather than try to figure this out for a quick project and possibly leave memory leaks, I've opted to use std::shared_ptr, which provides a similar worry-free behaviour.
#include <iostream>
#include <vector>
#include <cstdlib>
#include <memory>
template<class keyt, class valuet>
class LLRB {
private:
static const bool COLOR_RED = true;
static const bool COLOR_BLACK = false;
class Node {
public:
keyt key;
valuet val;
std::shared_ptr<Node> right;
std::shared_ptr<Node> left;
bool color;
Node(keyt key, valuet val){
this->key = key;
this->val = val;
this->color = COLOR_RED;
this->right = nullptr;
this->left = nullptr;
}
};
typedef std::shared_ptr<Node> nptr;
nptr root;
nptr rotateLeft(nptr h){
nptr x = h->right;
h->right = x->left;
x->left = h;
x->color = h->color;
h->color = COLOR_RED;
return x;
}
nptr rotateRight(nptr h){
nptr x = h->left;
h->left = x->right;
x->right = h;
x->color = h->color;
h->color = COLOR_RED;
return x;
}
nptr moveRedLeft(nptr h){
flipColors(h);
if(isRed(h->right->left)){
h->right = rotateRight(h->right);
h = rotateLeft(h);
flipColors(h);
}
return h;
}
nptr moveRedRight(nptr h){
flipColors(h);
if(isRed(h->left->left)){
h = rotateRight(h);
flipColors(h);
}
return h;
}
void flipColors(nptr h){
h->color = !h->color;
h->left->color = !h->left->color;
h->right->color = !h->right->color;
}
bool isRed(const nptr h) const {
if(h==nullptr) return false;
return h->color == COLOR_RED;
}
nptr fixUp(nptr h){
if(isRed(h->right) && !isRed(h->left)) h = rotateLeft (h);
if(isRed(h->left) && isRed(h->left->left)) h = rotateRight(h);
if(isRed(h->left) && isRed(h->right)) flipColors (h);
return h;
}
nptr insert(nptr h, keyt key, valuet val){
if(h==nullptr)
return std::make_shared<Node>(key,val);
if (key == h->key) h->val = val;
else if(key < h->key) h->left = insert(h->left, key,val);
else h->right = insert(h->right,key,val);
h = fixUp(h);
return h;
}
//This routine probably likes memory
nptr deleteMin(nptr h){
if(h->left==nullptr) return nullptr;
if(!isRed(h->left) && !isRed(h->left->left))
h = moveRedLeft(h);
h->left = deleteMin(h->left);
return fixUp(h);
}
nptr minNode(nptr h){
return (h->left == nullptr) ? h : minNode(h->left);
}
//This routine leaks memory like no other!! I've added a few cleanups
nptr remove(nptr h, keyt key){
if(key<h->key){
if(!isRed(h->left) && !isRed(h->left->left))
h = moveRedLeft(h);
h->left = remove(h->left, key);
} else {
if(isRed(h->left))
h = rotateRight(h);
if(key==h->key && h->right==nullptr)
return nullptr;
if(!isRed(h->right) && !isRed(h->right->left))
h = moveRedRight(h);
if(key==h->key){
std::shared_ptr<Node> mn = minNode(h->right);
h->val = mn->val;
h->key = mn->key;
h->right = deleteMin(h->right);
} else {
h->right = remove(h->right, key);
}
}
return fixUp(h);
}
void traverse(const nptr h) const {
if(h==nullptr)
return;
traverse(h->left);
std::cout<< h->key << "=" << h->val <<std::endl;
traverse(h->right);
}
public:
LLRB(){
root = nullptr;
}
void traverse() const {
traverse(root);
}
valuet search(keyt key){
nptr x = root;
while(x!=nullptr){
if (key == x->key) return x->val;
else if (key < x->key) x=x->left;
else x=x->right;
}
return keyt();
}
void insert(keyt key, valuet val){
root = insert(root,key,val);
root->color = COLOR_BLACK;
}
void remove(keyt key){
root = remove(root,key);
root->color = COLOR_BLACK;
}
};
int main(){
for(int test=0;test<500;test++){
LLRB<int,int> llrb;
std::vector<int> keys;
std::vector<int> vals;
for(int i=0;i<1000;i++){
//Ensure each key is unique
int newkey = rand();
while(llrb.search(newkey)!=int())
newkey = rand();
keys.push_back(newkey);
vals.push_back(rand()+1);
llrb.insert(keys.back(),vals.back());
}
//llrb.traverse();
for(int i=0;i<1000;i++){
if(llrb.search(keys[i])!=vals[i]){
return -1;
}
}
for(int i=0;i<500;i++)
llrb.remove(keys[i]);
for(int i=500;i<1000;i++){
if(llrb.search(keys[i])!=vals[i]){
return -1;
}
}
}
std::cout<<"Good"<<std::endl;
}
I'm building a Red-Black Tree, but may be there are some problems with my class RBTree's destructor. I add 10^7 value to the tree, and then call the destructor, but the memory seem to be not freed up. (I look at the System Monitor and my program still use 200MB).
Could you tell me what is wrong with my destructor. This is my source code.
Sorry for my poor English.
#include<cstdio>
#include<cstdlib>
#include<iostream>
using namespace std;
enum Color {RED, BLACK};
template<class Data> class RBNode;
template<class Data> class RBTree;
template<class Data> class RBNode {
Color color; RBNode *p, *left, *right;
public:
Data v;
RBNode(Color color, RBNode *p, RBNode *left, RBNode *right, Data v):
color(color), p(p), left(left), right(right), v(v) {}
RBNode() {}
friend class RBTree<Data>;
};
template<class Data> class RBTree {
typedef RBNode<Data> Node;
typedef Node * PNode;
PNode root, nil;
void LeftRotate(PNode x) {
PNode y = x->right; x->right = y->left;
if(y->left != nil) y->left->p = x;
y->p = x->p;
if(x->p == nil) root = y;
else if(x == x->p->left) x->p->left = y;
else x->p->right = y;
y->left = x; x->p = y;
}
void RightRotate(PNode y) {
PNode x = y->left; y->left = x->right;
if(x->right != nil) x->right->p = y;
x->p = y->p;
if(y->p == nil) root = x;
else if(y == y->p->left) y->p->left = x;
else y->p->right = x;
x->right = y; y->p = x;
}
void insertFixUp(PNode z) {
while(z->p->color == RED) {
if(z->p == z->p->p->left) {
PNode y = z->p->p->right;
if(y->color == RED) z->p->color = y->color = BLACK, z->p->p->color = RED, z = z->p->p;
else {
if(z == z->p->right) LeftRotate(z = z->p);
z->p->color = BLACK; z->p->p->color = RED; RightRotate(z->p->p);
}
} else {
PNode y = z->p->p->left;
if(y->color == RED) z->p->color = y->color = BLACK, z->p->p->color = RED, z = z->p->p;
else {
if(z == z->p->left) RightRotate(z = z->p);
z->p->color = BLACK; z->p->p->color = RED; LeftRotate(z->p->p);
}
}
}
root->color = BLACK;
}
public:
RBTree() {
nil = new Node;
nil->color = BLACK;
nil->p = nil->left = nil->right = nil;
nil->v = Data();
root = nil;
}
~RBTree() {
delete root;
delete nil;
}
void insert(Data v) {
PNode y = nil, x = root;
while(x != nil) {
y = x;
x = v < x->v ? x->left : x->right;
}
PNode z = new Node; *z = Node(RED, y, nil, nil, v);
if(y == nil) root = z;
else if(v < y->v) y->left = z;
else y->right = z;
insertFixUp(z);
}
};
int main() {
RBTree<int> tree;
for(int i = 0; i < 10000000; ++i) tree.insert(i);
tree.~RBTree();
getchar();
return 0;
}
You need to add a destructor to your RBNode, which deletes its children:
template<class Data> class RBNode {
...
~RBNode() {
delete left;
delete right;
}
...
};
As is, you will delete the root node when the tree is deleted, but the root node itself doesn't free its resources. Because of this, you lose all references to the child nodes of root, and all their child nodes, etc. Because you no longer have a reference to these nodes, you can't delete them, you have a memory leak.
The destructor ensures that when we're about to lose our references to a node's children, these children get freed (and their children and so on).
First, what's wrong with it is that you did not use a smart pointer. Secondly, you did not use a smart pointer in your Node classes, so when the root is deleted, none of the other objects are deleted.
Your tree nodes don't appear to recursively delete their children. You need a destructor in the node and then everything will cascade when the root gets destroyed.
Your destructor only frees up two elements: root and nil. To free up the rest of the tree, you should somehow propagate freeing up the elements down the tree, like:
~RBNode() {
if (left != nil ) delete left;
if (right != nil) delete right;
}
(this is just the idea, of course this code won't literally work because you don't see nil in the destructor).
I found my destructor, but i had some more attributes, like size and the parent pointer, but i think it will help
~RBTree() {
RBNode *p(root);
while(size!=0) {
if(p==root && size==1) { delete root; size--;}
else if(p->right!=0) p=p->right;
else if(p->left!=0) p=p->left;
else {
RBNode *c(p);
p=p->parent;
if(p->left==c) {
delete c;
p->left=0;
}
else {
delete c;
p->right=0;
}
size--;
}
}
}