Now the rbt.h file that needs to be included by the test program above ...
/* rbt.h */ /* 2014-11-06 */
/*
This file is an edited version of example code found at:
Eternally Confuzzled - Red Black Tree Tutorial.htm
Article was placed by its author, Julienne Walker, into 'Public Domain'
*/
#include <stdio.h>
#include <stdlib.h>
#define MAX_DEPTH_EXPECTED 50 /* for pre-fixed max size stack used in Traversal */
typedef struct myNode
{
int red;
int data;
struct myNode* link[2]; /* link[0] holds 'left' pointer,
link[1] holds the 'right' ... */
} Node ;
typedef struct myTree
{
Node* root;
int size;
} Tree ;
void initTree( Tree* tr )
{
tr->root = 0;
tr->size = 0;
}
int isRed( Node* root )
{
return root && root->red;
}
/* a non-recursive find... */
Node* findVal_nr( Tree* tr, int val )
{
Node* cur = tr->root;
while( cur && cur->data != val )
{
int dir = cur->data < val;
cur = cur->link[dir];
}
return cur;
}
/* a recursive find... */
Node* findVal_r( Node* cur, int val )
{
if ( !cur )
return cur;
else if ( cur->data == val )
return cur;
else
{
int dir = cur->data < val;
return findVal_r ( cur->link[dir], val );
}
}
Node* findVal( Tree* tr, int val )
{
return findVal_r( tr->root, val );
}
Node* rotate1( Node* root, int dir )
{
Node* save = root->link[!dir];
root->link[!dir] = save->link[dir];
save->link[dir] = root;
root->red = 1;
save->red = 0;
return save;
}
Node* rotate2( Node* root, int dir )
{
root->link[!dir] = rotate1( root->link[!dir], !dir );
return rotate1( root, dir );
}
/* test if really is a Red Black Tree, i.e. conditions hold ... */
int isRBT( Node* root )
{
int lh, rh;
if( root == 0 )
return 1;
else
{
Node* ln = root->link[0];
Node* rn = root->link[1];
/* Consecutive red links */
if ( isRed( root ) )
{
if( isRed( ln ) || isRed( rn ) )
{
puts( "Red violation" );
return 0;
}
}
lh = isRBT( ln );
rh = isRBT( rn );
/* Invalid binary search tree */
if( ( ln && ln->data >= root->data )
|| ( rn && rn->data <= root->data ) )
{
puts( "Binary tree violation" );
return 0;
}
/* Black height mismatch */
if( lh && rh && lh != rh )
{
puts( "Black violation" );
return 0;
}
/* Only count black links */
if( lh && rh )
return isRed( root ) ? lh : lh + 1;
else
return 0;
}
}
Node* makeNode ( int data )
{
Node* rn = malloc( sizeof(Node) );
if( rn )
{
rn->data = data;
rn->red = 1; /* 1 is red, 0 is black */
rn->link[0] = 0;
rn->link[1] = 0;
}
return rn;
}
/* a recursive insert... */
Node* insertVal_r( Node* root, int data, int* size )
{
if( !root )
{ root = makeNode( data ); ++ *size; }
else if( root->data != data )
{
int dir = root->data < data;
root->link[dir] = insertVal_r( root->link[dir], data, size );
if( isRed ( root->link[dir] ) )
{
if( isRed ( root->link[!dir] ) )
{
/* Case 1 */
root->red = 1;
root->link[0]->red = 0;
root->link[1]->red = 0;
}
else
{
/* Cases 2 & 3 */
if( isRed ( root->link[dir]->link[dir] ) )
root = rotate1( root, !dir );
else if( isRed ( root->link[dir]->link[!dir] ) )
root = rotate2( root, !dir );
}
}
}
return root;
}
int insertVal( Tree* tr, int data )
{
tr->root = insertVal_r( tr->root, data, &tr->size );
tr->root->red = 0;
return tr->size;
}
/* a non-recursive insert... */
int insertVal_nr ( Tree *tr, int data )
{
int sav_size = tr->size;
if ( !tr->root )
{
/* Empty tr case */
tr->root = makeNode ( data );
if ( !tr->root )
return 0;
else ++ tr->size;
}
else
{
Node head = {0}; /* False Tree root */
Node *g, *t; /* Grandparent & parent */
Node *p, *q; /* Iterator & parent */
int dir = 0, last;
/* Set up helpers */
t = &head;
g = p = NULL;
q = t->link[1] = tr->root;
/* Search down the Tree */
for ( ; ; )
{
if ( !q )
{
/* Insert new node at the bottom */
p->link[dir] = q = makeNode ( data );
if ( !q )
return 0;
else ++ tr->size;
}
else if ( isRed ( q->link[0] ) && isRed ( q->link[1] ) )
{
/* Color flip */
q->red = 1;
q->link[0]->red = 0;
q->link[1]->red = 0;
}
/* Fix red violation */
if ( isRed ( q ) && isRed ( p ) )
{
int dir2 = t->link[1] == g;
if ( q == p->link[last] )
t->link[dir2] = rotate1 ( g, !last );
else
t->link[dir2] = rotate2 ( g, !last );
}
/* Stop if found */
if ( q->data == data )
break;
last = dir;
dir = q->data < data;
/* Update helpers */
if ( g )
t = g;
g = p, p = q;
q = q->link[dir];
}
/* Update root */
tr->root = head.link[1];
}
/* Make root black */
/* if reach here ... tr->root) != 0 ... */
tr->root->red = 0;
return sav_size < tr->size;
}
/* a non-recursive remove... */
int removeVal_nr ( Tree* tr, int data )
{
int sav_size = tr->size;
if ( tr->root )
{
Node head = {0}; /* False tree root */
Node *q, *p, *g; /* Helpers */
Node *f = 0; /* Found item */
int dir = 1;
/* Set up helpers */
q = &head;
g = p = 0;
q->link[1] = tr->root;
/* Search and push a red down */
while ( q->link[dir] )
{
int last = dir;
/* Update helpers */
g = p, p = q;
q = q->link[dir];
dir = q->data < data;
/* Save found node */
if ( q->data == data )
f = q;
/* Push the red node down */
if ( !isRed ( q ) && !isRed ( q->link[dir] ) )
{
if ( isRed ( q->link[!dir] ) )
p = p->link[last] = rotate1 ( q, dir );
else if ( !isRed ( q->link[!dir] ) )
{
Node *s = p->link[!last];
if ( s )
{
if ( !isRed ( s->link[!last] ) && !isRed ( s->link[last] ) )
{
/* Color flip */
p->red = 0;
s->red = 1;
q->red = 1;
}
else
{
int dir2 = g->link[1] == p;
if ( isRed ( s->link[last] ) )
g->link[dir2] = rotate2 ( p, last );
else if ( isRed ( s->link[!last] ) )
g->link[dir2] = rotate1 ( p, last );
/* Ensure correct colouring */
q->red = g->link[dir2]->red = 1;
g->link[dir2]->link[0]->red = 0;
g->link[dir2]->link[1]->red = 0;
}
}
}
}
}
/* Replace and remove if found */
if ( f )
{
f->data = q->data;
p->link[p->link[1] == q] = q->link[q->link[0] == 0];
free ( q );
--tr->size;
}
/* Update root and make it black */
tr->root = head.link[1];
if( tr->root )
tr->root->red = 0;
}
return tr->size < sav_size;;
}
/* for the recursive remove... */
Node* remove_balance ( Node* root, int dir, int* done )
{
Node* p = root;
Node* s = root->link[!dir];
/* Case reduction, remove red sibling */
if ( isRed ( s ) )
{
root = rotate1 ( root, dir );
s = p->link[!dir];
}
if ( s != 0 )
{
if ( !isRed ( s->link[0] ) && !isRed ( s->link[1] ) )
{
if ( isRed ( p ) )
*done = 1;
p->red = 0;
s->red = 1;
}
else
{
int save = p->red;
int new_root = ( root == p );
if ( isRed ( s->link[!dir] ) )
p = rotate1 ( p, dir );
else
p = rotate2 ( p, dir );
p->red = save;
p->link[0]->red = 0;
p->link[1]->red = 0;
if ( new_root )
root = p;
else
root->link[dir] = p;
*done = 1;
}
}
return root;
}
/* for the recursive remove... */
Node* remove_r ( Node* root, int data, int* done, int* size )
{
if ( !root )
*done = 1;
else
{
int dir;
if ( root->data == data )
{
if ( root->link[0] == 0 || root->link[1] == 0 )
{
Node* save = root->link[root->link[0] == 0];
/* Case 0 */
if ( isRed ( root ) )
*done = 1;
else if ( isRed ( save ) )
{
save->red = 0;
*done = 1;
}
free ( root );
-- *size;
return save;
}
else
{
Node* heir = root->link[0];
while ( heir->link[1] != 0 )
heir = heir->link[1];
root->data = heir->data;
data = heir->data;
}
}
dir = root->data < data;
root->link[dir] = remove_r ( root->link[dir], data, done, size );
if ( !*done )
root = remove_balance ( root, dir, done );
}
return root;
}
/* a recursive remove... */
int removeVal ( Tree* tr, int data )
{
int done = 0, sav_size = tr->size;
tr->root = remove_r ( tr->root, data, &done, &tr->size );
if ( tr->root )
tr->root->red = 0;
return tr->size < sav_size;
}
/* recursive... */
void printInOrder( const Node* root )
{
if( root )
{
printInOrder(root->link[0] );
printf( " %d", root->data );
printInOrder(root->link[1] );
}
}
/* recursive... */
void printInPreOrder( const Node* root )
{
if( root )
{
printf( " %d", root->data );
printInPreOrder(root->link[0] );
printInPreOrder(root->link[1] );
}
}
/* recursive... */
void printInPostOrder( const Node* root )
{
if( root )
{
printInPostOrder(root->link[0] );
printInPostOrder(root->link[1] );
printf( " %d", root->data );
}
}
/* non_recursive... ***ASSUMES NONE EMPTY TREE*** */
Node* minVal( Node* root )
{
Node* cur = root;
while( cur && cur->link[0] ) cur = cur->link[0];
return cur;
}
/* non_recursive... ***ASSUMES NONE EMPTY TREE*** */
Node* maxVal( Node* root )
{
Node* cur = root;
while( cur && cur->link[1] ) cur = cur->link[1];
return cur;
}
/* Note: the '_r' indicates that this is a recursive function ... */
void destroyTree_r ( Node* cur )
{
if ( cur )
{
/* Note: using a 'postorder' traversalersal ...
so each 'root' is a 'leaf' */
destroyTree_r ( cur->link[0] );
destroyTree_r ( cur->link[1] );
free ( cur );
}
}
void destroyTree ( Tree* tr )
{
destroyTree_r ( tr->root );
initTree( tr );
}
typedef struct myTraversal
{
Node* up[MAX_DEPTH_EXPECTED]; /* Stack */
Node* it; /* Current node */
int top; /* Top of stack */
} Traversal ;
Node* traversalBegin ( Tree *tre, Traversal* trv )
{
trv->it = tre->root;
trv->top = 0; /* now initial values are ser ... */
if ( trv->it )
{
while ( trv->it->link[0] )
{
trv->up[trv->top++] = trv->it;
trv->it = trv->it->link[0];
}
}
return trv->it;
}
Node* traversalNext ( Traversal* trv )
{
if ( trv->it->link[1] )
{
trv->up[trv->top++] = trv->it;
trv->it = trv->it->link[1];
while ( trv->it->link[0] )
{
trv->up[trv->top++] = trv->it;
trv->it = trv->it->link[0];
}
}
else
{
Node* last;
do
{
if ( !trv->top )
{
trv->it = 0;
break;
}
last = trv->it;
trv->it = trv->up[--trv->top];
}
while ( last == trv->it->link[1] );
}
return trv->it;
}