Browse Source

rbtree insert and delete now as one function and working as expected...still has to be checked on sideeffects.

release0.1.5
Georg Hopp 12 years ago
parent
commit
ef6ccfbcbe
  1. 315
      src/rbtree.c

315
src/rbtree.c

@ -89,7 +89,7 @@ sibling(struct element * node)
}
/*
* rotations...also needed for rb handling.
* tree modifications...needed for rb handling.
*/
void
rotateLeft(struct element ** tree, struct element * node)
@ -139,6 +139,23 @@ rotateRight(struct element ** tree, struct element * node)
node->parent = leftChild;
}
void
replaceNode(struct element * node1, struct element * node2)
{
if (NULL != node1->parent) {
if (node1 == node1->parent->left) {
node1->parent->left = node2;
} else {
node1->parent->right = node2;
}
}
if (NULL != node2) {
node2->parent = node1->parent;
}
}
/**
* insert element in tree
*/
@ -270,6 +287,9 @@ struct element *
deleteElement(struct element ** tree, int data)
{
struct element * node = *tree;
struct element * del_node;
struct element * child;
struct element * s;
// find the relevant node and it's parent
while (NULL != node && node->data != data) {
@ -285,137 +305,107 @@ deleteElement(struct element ** tree, int data)
return node;
}
del_node = node;
// now our cases follows...the first one is the same as with
// simple binary search trees.
// simple binary search trees. Two non null children.
// case 1: two children
if (NULL != node->left && NULL != node->right) {
struct element * successor = findInOrderSuccessor(node);
node->data = successor->data;
node = successor;
del_node = node = successor;
}
return deleteOneChild(tree, node);
}
void
traverse(struct element * tree, void (*cb)(int, int))
{
struct element * previous = tree;
struct element * node = tree;
int depth = 1;
/*
* I think this has something like O(n+log(n)) on a ballanced
* tree because I have to traverse back the rightmost leaf to
* the root to get a break condition.
*/
while (node) {
/*
* If we come from the right so nothing and go to our
* next parent.
*/
if (previous == node->right) {
previous = node;
node = node->parent;
depth--;
continue;
}
if ((NULL == node->left || previous == node->left)) {
/*
* If there are no more elements to the left or we
* came from the left, process data.
*/
cb(node->data, depth);
previous = node;
// delete and rb rebalance...
while(1) {
// Precondition: n has at most one non-null child.
child = (NULL == node->right) ? node->left : node->right;
replaceNode(node, child);
if (NULL != node->right) {
node = node->right;
depth++;
// delete one child case
// TODO this is overly complex as simply derived from the function...
// maybe this can be simplified. Maybe not...check.
if (node->color == rbBlack) {
if (NULL != child && child->color == rbRed) {
child->color = rbBlack;
// done despite modifying tree itself if neccessary..
break;
} else {
node = node->parent;
depth--;
if (NULL == node->parent){
*tree = 0x0;
}
} else {
/*
* if there are more elements to the left go there.
*/
previous = node;
node = node->left;
depth++;
node = child;
}
} else {
if (NULL == node->parent){
*tree = 0x0;
}
break;
}
void printElement(int data, int depth)
{
int i;
printf("%02d(%02d)", data, depth);
for (i=0; i<depth; i++) printf("-");
puts("");
// case 1
if (NULL == node || NULL == node->parent) {
// done again
break;
}
// case 2
s = sibling(node);
void
replaceNode(struct element * node1, struct element * node2)
{
if (NULL != node1->parent) {
if (node1 == node1->parent->left) {
node1->parent->left = node2;
} else {
node1->parent->right = node2;
}
}
if (NULL != s && s->color == rbRed) {
node->parent->color = rbRed;
s->color = rbBlack;
if (NULL != node2) {
node2->parent = node1->parent;
if (node == node->parent->left) {
rotateLeft(tree, node->parent);
} else {
rotateRight(tree, node->parent);
}
}
void
deleteCase6(struct element ** tree, struct element * node)
{
struct element * s = sibling(node);
// case 3 / 4
if (NULL == s || ((s->color == rbBlack) &&
(s->left->color == rbBlack) &&
(s->right->color == rbBlack))) {
s->color = node->parent->color;
node->parent->color = rbBlack;
if (NULL != s) {
s->color = rbRed;
}
if (node == node->parent->left) {
s->right->color = rbBlack;
rotateLeft(tree, node->parent);
if (node->parent->color == rbBlack) {
// case 3
node = node->parent;
continue;
} else {
s->left->color = rbBlack;
rotateRight(tree, node->parent);
// case 4
node->parent->color = rbBlack;
// and done again...
break;
}
} else {
// done...
break;
}
void
deleteCase5(struct element ** tree, struct element * node)
{
struct element * s = sibling(node);
// case 5
if (NULL != s && s->color == rbBlack) {
/*
* this if statement is trivial,
* due to case 2 (even though case 2 changed the sibling to a
* sibling's child,
* the sibling's child can't be red, since no red parent can
* have a red child).
*/
/*
* the following statements just force the red to be on the
* left of the left of the parent,
* or right of the right, so case six will rotate correctly.
*/
// this if statement is trivial,
// due to case 2 (even though case 2 changed the sibling to a
// sibling's child,
// the sibling's child can't be red, since no red parent can
// have a red child).
//
// the following statements just force the red to be on the
// left of the left of the parent,
// or right of the right, so case 6 will rotate correctly.
if ((node == node->parent->left) &&
(s->right->color == rbBlack) &&
(s->left->color == rbRed)) {
/* this last test is trivial too due to cases 2-4. */
// this last test is trivial too due to cases 2-4.
s->color = rbRed;
s->left->color = rbBlack;
@ -423,9 +413,7 @@ deleteCase5(struct element ** tree, struct element * node)
} else if ((node == node->parent->right) &&
(s->left->color == rbBlack) &&
(s->right->color == rbRed)) {
/*
* this last test is trivial too due to cases 2-4.
*/
// this last test is trivial too due to cases 2-4.
s->color = rbRed;
s->right->color = rbBlack;
@ -433,99 +421,86 @@ deleteCase5(struct element ** tree, struct element * node)
}
}
deleteCase6(tree, node);
}
void
deleteCase4(struct element ** tree, struct element * node)
{
struct element * s = sibling(node);
if ((node->parent->color == rbRed) &&
(NULL == s || ((s->color == rbBlack) &&
(s->left->color == rbBlack) &&
(s->right->color == rbBlack)))) {
if (NULL != s) {
s->color = rbRed;
}
// case 6
s->color = node->parent->color;
node->parent->color = rbBlack;
} else {
deleteCase5(tree, node);
}
}
void deleteCase1(struct element **, struct element *);
void
deleteCase3(struct element ** tree, struct element * node)
{
struct element * s = sibling(node);
if ((node->parent->color == rbBlack) &&
(NULL == s || ((s->color == rbBlack) &&
(s->left->color == rbBlack) &&
(s->right->color == rbBlack)))) {
if (NULL != s) {
s->color = rbRed;
}
deleteCase1(tree, node->parent);
} else {
deleteCase4(tree, node);
}
}
void
deleteCase2(struct element ** tree, struct element * node)
{
struct element * s = sibling(node);
if (NULL != s && s->color == rbRed) {
node->parent->color = rbRed;
s->color = rbBlack;
if (node == node->parent->left) {
s->right->color = rbBlack;
rotateLeft(tree, node->parent);
} else {
s->left->color = rbBlack;
rotateRight(tree, node->parent);
}
// done...
break;
}
deleteCase3(tree, node);
//deleteOneChild(tree, node);
return del_node;
}
void
deleteCase1(struct element ** tree, struct element * node)
traverse(struct element * tree, void (*cb)(int, int, enum rbColor))
{
if (NULL != node && NULL != node->parent) {
deleteCase2(tree, node);
}
}
struct element * previous = tree;
struct element * node = tree;
int depth = 1;
struct element *
deleteOneChild(struct element ** tree, struct element * node)
{
/*
* Precondition: n has at most one non-null child.
* I think this has something like O(n+log(n)) on a ballanced
* tree because I have to traverse back the rightmost leaf to
* the root to get a break condition.
*/
while (node) {
/*
* If we come from the right so nothing and go to our
* next parent.
*/
struct element * child = (NULL == node->right) ? node->left : node->right;
if (previous == node->right) {
previous = node;
node = node->parent;
depth--;
continue;
}
replaceNode(node, child);
if ((NULL == node->left || previous == node->left)) {
/*
* If there are no more elements to the left or we
* came from the left, process data.
*/
cb(node->data, depth, node->color);
previous = node;
if (node->color == rbBlack) {
if (NULL != child && child->color == rbRed) {
child->color = rbBlack;
if (NULL != node->right) {
node = node->right;
depth++;
} else {
node = node->parent;
depth--;
}
} else {
deleteCase1(tree, child);
/*
* if there are more elements to the left go there.
*/
previous = node;
node = node->left;
depth++;
}
}
if (NULL == node->parent){
*tree = 0x0;
}
return node;
}
void printElement(int data, int depth, enum rbColor color)
{
int i;
printf("%s %02d(%02d)", (color==rbRed)?"R":"B", data, depth);
for (i=0; i<depth; i++) printf("-");
puts("");
}
/**
@ -548,7 +523,6 @@ main(int argc, char * argv[])
puts("traverse");
traverse(root, printElement);
/*
free(deleteElement(&root, 8));
puts("traverse");
traverse(root, printElement);
@ -580,7 +554,6 @@ main(int argc, char * argv[])
free(deleteElement(&root, 12));
puts("traverse");
traverse(root, printElement);
*/
return 0;
}

Loading…
Cancel
Save