Browse Source

update todo and make my rbtree implementation use externally allocated elements.

release0.1.5
Georg Hopp 13 years ago
parent
commit
06266ef541
  1. 4
      TODO
  2. 259
      src/rbtree.c

4
TODO

@ -8,4 +8,6 @@ VERY BIG TODO:
- IPV6 support - IPV6 support
- There seem to be a problem in the server under heavy load. Some tests with ab show that at some point it does not accept any more connections. Nor does it seem to answer request. I guess that it might be difficult to find this.... - There seem to be a problem in the server under heavy load. Some tests with ab show that at some point it does not accept any more connections. Nor does it seem to answer request. I guess that it might be difficult to find this....
=> might be done...
=> might be done... maybe not completely, I still loose connections under very high load.
- using tsearch for my memory management was kind of a bad idea. tsearch uses malloc and free upon addition and remove of elements. Resulting again in uncontroolled heap usage. I guess I have to implement my own tree mechanism here, which does not involve further allocation.

259
src/rbtree.c

@ -1,6 +1,8 @@
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h>
#define NVALUES 10
enum rbColor {rbBlack=1, rbRed=2}; enum rbColor {rbBlack=1, rbRed=2};
@ -19,14 +21,15 @@ struct element
struct element * struct element *
newElement(int data) newElement(int data)
{ {
struct element * node = malloc(sizeof(struct element));
node->data = data;
node->color = rbRed;
node->parent = NULL;
node->left = NULL;
node->right = NULL;
struct element * element = malloc(sizeof(struct element));
return node;
element->data = data;
element->color = rbRed;
element->parent = NULL;
element->left = NULL;
element->right = NULL;
return element;
} }
/** /**
@ -83,9 +86,15 @@ uncle(struct element * node)
struct element * struct element *
sibling(struct element * node) sibling(struct element * node)
{ {
return (node == node->parent->left) ?
node->parent->right :
node->parent->left;
if (NULL == node) {
return NULL;
}
if (NULL == node->parent->left || node == node->parent->left) {
return node->parent->right;
} else {
return node->parent->left;
}
} }
/* /*
@ -100,7 +109,9 @@ rotateLeft(struct element ** tree, struct element * node)
rightChild->left = node; rightChild->left = node;
rightChild->parent = node->parent; rightChild->parent = node->parent;
node->right = rcLeftSub; node->right = rcLeftSub;
rcLeftSub->parent = node;
if (NULL != rcLeftSub) {
rcLeftSub->parent = node;
}
if (node->parent) { if (node->parent) {
if (node->parent->left == node) { if (node->parent->left == node) {
@ -124,7 +135,9 @@ rotateRight(struct element ** tree, struct element * node)
leftChild->right = node; leftChild->right = node;
leftChild->parent = node->parent; leftChild->parent = node->parent;
node->left = lcRightSub; node->left = lcRightSub;
lcRightSub->parent = node;
if (NULL != lcRightSub) {
lcRightSub->parent = node;
}
if (node->parent) { if (node->parent) {
if (node->parent->left == node) { if (node->parent->left == node) {
@ -140,7 +153,10 @@ rotateRight(struct element ** tree, struct element * node)
} }
void void
replaceNode(struct element * node1, struct element * node2)
replaceNode(
struct element ** tree,
struct element * node1,
struct element * node2)
{ {
if (NULL != node1->parent) { if (NULL != node1->parent) {
if (node1 == node1->parent->left) { if (node1 == node1->parent->left) {
@ -148,6 +164,8 @@ replaceNode(struct element * node1, struct element * node2)
} else { } else {
node1->parent->right = node2; node1->parent->right = node2;
} }
} else {
*tree = node2;
} }
if (NULL != node2) { if (NULL != node2) {
@ -160,7 +178,7 @@ replaceNode(struct element * node1, struct element * node2)
* insert element in tree * insert element in tree
*/ */
struct element * struct element *
insertElement(struct element ** tree, int data)
insertElement(struct element ** tree, struct element * element)
{ {
struct element * node = *tree; struct element * node = *tree;
struct element * new_node = NULL; struct element * new_node = NULL;
@ -169,28 +187,30 @@ insertElement(struct element ** tree, int data)
// if tree is empty it's simple... :) // if tree is empty it's simple... :)
if (NULL == node) { if (NULL == node) {
*tree = node = new_node = newElement(data);
*tree = node = new_node = element;
} else { } else {
// normal binary tree add.... // normal binary tree add....
while (data != node->data) {
if (data < node->data) {
while (element->data != node->data) {
if (element->data < node->data) {
if (NULL == node->left) { if (NULL == node->left) {
node->left = newElement(data);
node->left = element;
node->left->parent = node; node->left->parent = node;
new_node = node = node->left; new_node = node = node->left;
break; break;
} else { } else {
node = node->left; node = node->left;
} }
} else {
} else if (element->data > node->data) {
if (NULL == node->right) { if (NULL == node->right) {
node->right = newElement(data);
node->right = element;
node->right->parent = node; node->right->parent = node;
new_node = node = node->right; new_node = node = node->right;
break; break;
} else { } else {
node = node->right; node = node->right;
} }
} else {
return node;
} }
} }
} }
@ -217,7 +237,7 @@ insertElement(struct element ** tree, int data)
u = uncle(node); u = uncle(node);
g = grandparent(node); g = grandparent(node);
if ((u != NULL) && (u->color == rbRed)) {
if (u != NULL && u->color == rbRed) {
node->parent->color = rbBlack; node->parent->color = rbBlack;
u->color = rbBlack; u->color = rbBlack;
g->color = rbRed; g->color = rbRed;
@ -227,12 +247,10 @@ insertElement(struct element ** tree, int data)
} }
// case 4 // case 4
if ((node == node->parent->right) && (node->parent == g->left)) {
if (node == node->parent->right && node->parent == g->left) {
rotateLeft(tree, node->parent); rotateLeft(tree, node->parent);
node = node->left; node = node->left;
} else if (
(node == node->parent->left) &&
(node->parent == g->right)) {
} else if (node == node->parent->left && node->parent == g->right) {
rotateRight(tree, node->parent); rotateRight(tree, node->parent);
node = node->right; node = node->right;
@ -284,7 +302,7 @@ findInOrderSuccessor(struct element * tree)
struct element * deleteOneChild(struct element **, struct element *); struct element * deleteOneChild(struct element **, struct element *);
struct element * struct element *
deleteElement(struct element ** tree, int data)
deleteElement(struct element ** tree, struct element * element)
{ {
struct element * node = *tree; struct element * node = *tree;
struct element * del_node; struct element * del_node;
@ -292,8 +310,8 @@ deleteElement(struct element ** tree, int data)
struct element * s; struct element * s;
// find the relevant node and it's parent // find the relevant node and it's parent
while (NULL != node && node->data != data) {
if (data < node->data) {
while (NULL != node && node->data != element->data) {
if (element->data < node->data) {
node = node->left; node = node->left;
} else { } else {
node = node->right; node = node->right;
@ -318,35 +336,35 @@ deleteElement(struct element ** tree, int data)
del_node = node = successor; del_node = node = successor;
} }
// 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);
// 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 {
if (NULL == node->parent){
*tree = 0x0;
}
node = child;
}
// Precondition: n has at most one non-null child.
child = (NULL == node->right) ? node->left : node->right;
replaceNode(tree, node, child);
// 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..
return del_node;
} else { } else {
if (NULL == node->parent){
*tree = 0x0;
if (NULL != child) {
node = child;
} else {
node->color = rbBlack;
node->left = NULL;
node->right = NULL;
} }
break;
} }
} else {
return del_node;
}
// delete and rb rebalance...
while(1) {
// case 1 // case 1
if (NULL == node || NULL == node->parent) {
if (NULL == node->parent) {
// done again // done again
break; break;
} }
@ -358,17 +376,23 @@ deleteElement(struct element ** tree, int data)
node->parent->color = rbRed; node->parent->color = rbRed;
s->color = rbBlack; s->color = rbBlack;
if (node == node->parent->left) {
/*
* detect which child we are...assumption
* if we are not parent->right and parent->right is not
* null we must be left, even if its set to NULL previously
*/
if (NULL != node->parent->right && node != node->parent->right) {
rotateLeft(tree, node->parent); rotateLeft(tree, node->parent);
} else { } else {
rotateRight(tree, node->parent); rotateRight(tree, node->parent);
} }
} }
s = sibling(node);
// case 3 / 4 // case 3 / 4
if (NULL == s || ((s->color == rbBlack) && if (NULL == s || ((s->color == rbBlack) &&
(s->left->color == rbBlack) &&
(s->right->color == rbBlack))) {
(NULL == s->left || s->left->color == rbBlack) &&
(NULL == s->right || s->right->color == rbBlack))) {
if (NULL != s) { if (NULL != s) {
s->color = rbRed; s->color = rbRed;
@ -384,12 +408,8 @@ deleteElement(struct element ** tree, int data)
// and done again... // and done again...
break; break;
} }
} else {
// done...
break;
} }
// case 5 // case 5
if (NULL != s && s->color == rbBlack) { if (NULL != s && s->color == rbBlack) {
// this if statement is trivial, // this if statement is trivial,
@ -402,8 +422,8 @@ deleteElement(struct element ** tree, int data)
// left of the left of the parent, // left of the left of the parent,
// or right of the right, so case 6 will rotate correctly. // or right of the right, so case 6 will rotate correctly.
if ((node == node->parent->left) && if ((node == node->parent->left) &&
(s->right->color == rbBlack) &&
(s->left->color == rbRed)) {
(NULL == s->right || s->right->color == rbBlack) &&
(NULL != s->left && 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->color = rbRed;
@ -411,8 +431,8 @@ deleteElement(struct element ** tree, int data)
rotateRight(tree, s); rotateRight(tree, s);
} else if ((node == node->parent->right) && } else if ((node == node->parent->right) &&
(s->left->color == rbBlack) &&
(s->right->color == rbRed)) {
(NULL == s->left || s->left->color == rbBlack) &&
(NULL != s->right && 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->color = rbRed;
s->right->color = rbBlack; s->right->color = rbBlack;
@ -421,16 +441,31 @@ deleteElement(struct element ** tree, int data)
} }
} }
s = sibling(node);
// case 6 // case 6
s->color = node->parent->color;
node->parent->color = rbBlack;
if (NULL != s) {
s->color = node->parent->color;
}
if (node == node->parent->left) {
s->right->color = rbBlack;
rotateLeft(tree, node->parent);
} else {
s->left->color = rbBlack;
rotateRight(tree, node->parent);
if (NULL != node && NULL != node->parent) {
node->parent->color = rbBlack;
/*
* detect which child we are...assumption
* if we are not parent->right and parent->right is not
* null we must be left, even if its set to NULL previously
*/
if (NULL != node->parent->right && node != node->parent->right) {
if (NULL != s->right) {
s->right->color = rbBlack;
}
rotateLeft(tree, node->parent);
} else {
if (NULL != s->left) {
s->left->color = rbBlack;
}
rotateRight(tree, node->parent);
}
} }
// done... // done...
@ -509,49 +544,57 @@ void printElement(int data, int depth, enum rbColor color)
int int
main(int argc, char * argv[]) main(int argc, char * argv[])
{ {
struct element * root = NULL;
insertElement(&root, 13);
insertElement(&root, 8);
insertElement(&root, 16);
insertElement(&root, 11);
insertElement(&root, 3);
insertElement(&root, 9);
insertElement(&root, 12);
insertElement(&root, 10);
puts("traverse");
traverse(root, printElement);
free(deleteElement(&root, 8));
puts("traverse");
traverse(root, printElement);
free(deleteElement(&root, 11));
puts("traverse");
traverse(root, printElement);
free(deleteElement(&root, 13));
puts("traverse");
traverse(root, printElement);
free(deleteElement(&root, 3));
puts("traverse");
traverse(root, printElement);
struct element * root = NULL;
int value;
int count;
// insertElement(&root, newElement(84));
// insertElement(&root, newElement(87));
// insertElement(&root, newElement(78));
// insertElement(&root, newElement(16));
// insertElement(&root, newElement(94));
//
// puts("traverse");
// traverse(root, printElement);
//
// free(deleteElement(&root, findElement(root, 87)));
// puts("traverse");
// traverse(root, printElement);
// free(deleteElement(&root, findElement(root, 94)));
// puts("traverse");
// traverse(root, printElement);
// free(deleteElement(&root, findElement(root, 16)));
// puts("traverse");
// traverse(root, printElement);
// free(deleteElement(&root, findElement(root, 84)));
// puts("traverse");
// traverse(root, printElement);
// free(deleteElement(&root, findElement(root, 78)));
// puts("traverse");
// traverse(root, printElement);
//
for (count=0; count<NVALUES;) {
value = (random() % 1000000) + 1;
if (NULL == findElement(root, value)) {
insertElement(&root, newElement(value));
count++;
}
}
free(deleteElement(&root, 16));
puts("traverse"); puts("traverse");
traverse(root, printElement); traverse(root, printElement);
free(deleteElement(&root, 10));
puts("traverse");
traverse(root, printElement);
for (count=0; count<NVALUES;) {
value = (random() % 1000000) + 1;
struct element * element = findElement(root, value);
free(deleteElement(&root, 9));
puts("traverse");
traverse(root, printElement);
if (NULL != element) {
free(deleteElement(&root, element));
count++;
}
}
free(deleteElement(&root, 12));
puts("traverse"); puts("traverse");
traverse(root, printElement); traverse(root, printElement);

Loading…
Cancel
Save