A task management system. At least this was the initial idea. Basically this it the base code for the taskrambler framework.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

588 lines
13 KiB

#include <stdio.h>
#include <stdlib.h>
enum rbColor {rbBlack=1, rbRed=2};
struct element
{
int data;
enum rbColor color;
struct element * parent;
struct element * left;
struct element * right;
};
struct element *
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;
return node;
}
/**
* find element in tree
*/
struct element *
findElement(struct element * tree, int data)
{
while (NULL != tree) {
if (tree->data == data) {
break;
}
if (data < tree->data) {
tree = tree->left;
} else {
tree = tree->right;
}
}
return tree;
}
/*
* function to get specific elements needed for
* rb handling, grandparent, uncle and sibbling
*/
struct element *
grandparent(struct element * node)
{
if (NULL != node && NULL != node->parent) {
return node->parent->parent;
}
return NULL;
}
struct element *
uncle(struct element * node)
{
struct element * gp = grandparent(node);
if (NULL == gp) {
return NULL;
}
if (node->parent == gp->left) {
return gp->right;
}
return gp->left;
}
struct element *
sibling(struct element * node)
{
return (node == node->parent->left) ?
node->parent->right :
node->parent->left;
}
/*
* rotations...also needed for rb handling.
*/
void
rotateLeft(struct element ** tree, struct element * node)
{
struct element * rightChild = node->right;
struct element * rcLeftSub = node->right->left;
rightChild->left = node;
rightChild->parent = node->parent;
node->right = rcLeftSub;
rcLeftSub->parent = node;
if (node->parent) {
if (node->parent->left == node) {
node->parent->left = rightChild;
} else {
node->parent->right = rightChild;
}
} else {
*tree = rightChild;
}
node->parent = rightChild;
}
void
rotateRight(struct element ** tree, struct element * node)
{
struct element * leftChild = node->left;
struct element * lcRightSub = node->left->right;
leftChild->right = node;
leftChild->parent = node->parent;
node->left = lcRightSub;
lcRightSub->parent = node;
if (node->parent) {
if (node->parent->left == node) {
node->parent->left = leftChild;
} else {
node->parent->right = leftChild;
}
} else {
*tree = leftChild;
}
node->parent = leftChild;
}
/**
* insert element in tree
*/
struct element *
insertElement(struct element ** tree, int data)
{
struct element * node = *tree;
struct element * new_node = NULL;
struct element * u;
struct element * g;
// if tree is empty it's simple... :)
if (NULL == node) {
*tree = node = new_node = newElement(data);
} else {
// normal binary tree add....
while (data != node->data) {
if (data < node->data) {
if (NULL == node->left) {
node->left = newElement(data);
node->left->parent = node;
new_node = node = node->left;
break;
} else {
node = node->left;
}
} else {
if (NULL == node->right) {
node->right = newElement(data);
node->right->parent = node;
new_node = node = node->right;
break;
} else {
node = node->right;
}
}
}
}
if (NULL != new_node) {
/*
* handle reballancing rb style
*/
while (1) {
// case 1
if (node->parent == NULL) {
node->color = rbBlack;
// we're done.... :)
break;
}
// case 2
if (node->parent->color == rbBlack) {
// Tree is still valid ... wow, again we're done... :)
break;
}
// case 3
u = uncle(node);
g = grandparent(node);
if ((u != NULL) && (u->color == rbRed)) {
node->parent->color = rbBlack;
u->color = rbBlack;
g->color = rbRed;
node = g;
continue;
}
// case 4
if ((node == node->parent->right) && (node->parent == g->left)) {
rotateLeft(tree, node->parent);
node = node->left;
} else if (
(node == node->parent->left) &&
(node->parent == g->right)) {
rotateRight(tree, node->parent);
node = node->right;
}
// case 5
g = grandparent(node);
node->parent->color = rbBlack;
g->color = rbRed;
if (node == node->parent->left) {
rotateRight(tree, g);
} else {
rotateLeft(tree, g);
}
// we're done..
break;
}
}
return new_node;
}
/**
* delete element from tree
* here multiple functions are involved....
* =======================================================================
*/
/**
* find minimum of the right subtree aka leftmost leaf of right subtree
* aka left in-order successor.
* We return the parent of the element in the out argument parent.
* This can be NULL wenn calling.
*/
struct element *
findInOrderSuccessor(struct element * tree)
{
struct element * node = tree->right;
while (NULL != node->left) {
node = node->left;
}
return node;
}
struct element * deleteOneChild(struct element **, struct element *);
struct element *
deleteElement(struct element ** tree, int data)
{
struct element * node = *tree;
// find the relevant node and it's parent
while (NULL != node && node->data != data) {
if (data < node->data) {
node = node->left;
} else {
node = node->right;
}
}
// element not found
if (NULL == node) {
return node;
}
// now our cases follows...the first one is the same as with
// simple binary search trees.
// case 1: two children
if (NULL != node->left && NULL != node->right) {
struct element * successor = findInOrderSuccessor(node);
node->data = successor->data;
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;
if (NULL != node->right) {
node = node->right;
depth++;
} else {
node = node->parent;
depth--;
}
} else {
/*
* if there are more elements to the left go there.
*/
previous = node;
node = node->left;
depth++;
}
}
}
void printElement(int data, int depth)
{
int i;
printf("%02d(%02d)", data, depth);
for (i=0; i<depth; i++) printf("-");
puts("");
}
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;
}
}
void
deleteCase6(struct element ** tree, struct element * node)
{
struct element * s = sibling(node);
s->color = node->parent->color;
node->parent->color = rbBlack;
if (node == node->parent->left) {
s->right->color = rbBlack;
rotateLeft(tree, node->parent);
} else {
s->left->color = rbBlack;
rotateRight(tree, node->parent);
}
}
void
deleteCase5(struct element ** tree, struct element * node)
{
struct element * s = sibling(node);
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.
*/
if ((node == node->parent->left) &&
(s->right->color == rbBlack) &&
(s->left->color == rbRed)) {
/* this last test is trivial too due to cases 2-4. */
s->color = rbRed;
s->left->color = rbBlack;
rotateRight(tree, s);
} 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.
*/
s->color = rbRed;
s->right->color = rbBlack;
rotateLeft(tree, s);
}
}
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;
}
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) {
rotateLeft(tree, node->parent);
} else {
rotateRight(tree, node->parent);
}
}
deleteCase3(tree, node);
}
void
deleteCase1(struct element ** tree, struct element * node)
{
if (NULL != node && NULL != node->parent) {
deleteCase2(tree, node);
}
}
struct element *
deleteOneChild(struct element ** tree, struct element * node)
{
/*
* Precondition: n has at most one non-null child.
*/
struct element * child = (NULL == node->right) ? node->left : node->right;
replaceNode(node, child);
if (node->color == rbBlack) {
if (NULL != child && child->color == rbRed) {
child->color = rbBlack;
} else {
deleteCase1(tree, child);
}
}
if (NULL == node->parent){
*tree = 0x0;
}
return node;
}
/**
* =======================================================================
*/
int
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);
free(deleteElement(&root, 16));
puts("traverse");
traverse(root, printElement);
free(deleteElement(&root, 10));
puts("traverse");
traverse(root, printElement);
free(deleteElement(&root, 9));
puts("traverse");
traverse(root, printElement);
free(deleteElement(&root, 12));
puts("traverse");
traverse(root, printElement);
*/
return 0;
}
// vim: set et ts=4 sw=4: