├── .gitignore ├── CHANGES ├── LICENSE ├── Makefile ├── README.md ├── container.c ├── container.h ├── fuzz_red_black_tree.c ├── misc.c ├── misc.h ├── red_black_tree.c ├── red_black_tree.h ├── simple_test.sh ├── stack.c ├── stack.h └── test_red_black_tree.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | 4 | # Libraries 5 | *.lib 6 | *.a 7 | 8 | # Shared objects (inc. Windows DLLs) 9 | *.dll 10 | *.so 11 | *.so.* 12 | *.dylib 13 | 14 | # Executables 15 | *.exe 16 | *.out 17 | *.app 18 | -------------------------------------------------------------------------------- /CHANGES: -------------------------------------------------------------------------------- 1 | 2 | Sun Jan 09, 2005: I fixed a bug that caused the test_rb program to 3 | go into an infinite loop if the user entered an 4 | invalid key. Thanks to Amores Perros for pointing 5 | out this problem. 6 | 7 | Wed Sep 19, 2001: I fixed some bugs and memory leaks pointed out 8 | by Brett Donahue and added some rudimentary 9 | memory checking tests to the makefile. 10 | 11 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Redistribution and use in source and binary forms, with or without 3 | modification, are permitted provided that neither the name of Emin 4 | Martinian nor the names of any contributors are be used to endorse or 5 | promote products derived from this software without specific prior 6 | written permission. 7 | 8 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 9 | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 10 | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 11 | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 12 | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 13 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 14 | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 15 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 16 | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 17 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 18 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 19 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | # prompt> make 3 | # builds everything and links in test program test_rb 4 | # 5 | # prompt> make mem_check 6 | # Rebuilds everything using dmalloc and does memory testing. 7 | # Only works if you have dmalloc installed (see http://dmalloc.com). 8 | 9 | SRCS = test_red_black_tree.c red_black_tree.c stack.c misc.c 10 | 11 | HDRS = red_black_tree.h stack.h misc.h 12 | 13 | OBJS = red_black_tree.o stack.o test_red_black_tree.o misc.o 14 | 15 | OBJS2 = red_black_tree.o stack.o fuzz_red_black_tree.o misc.o container.o 16 | 17 | CC = gcc 18 | #CC = clang -fsanitize=address,undefined 19 | 20 | #CFLAGS = -g -O0 -coverage -fprofile-arcs -Wall -pedantic 21 | CFLAGS = -O3 -Wall -pedantic 22 | 23 | PROGRAM = test_rb 24 | 25 | PROGRAM2 = fuzz_rb 26 | 27 | .PHONY: mem_check clean 28 | 29 | all: $(PROGRAM) $(PROGRAM2) 30 | 31 | $(PROGRAM): $(OBJS) 32 | $(CC) $(CFLAGS) $(OBJS) -o $(PROGRAM) $(DMALLOC_LIB) 33 | 34 | $(PROGRAM2): $(OBJS2) 35 | $(CC) $(CFLAGS) $(OBJS2) -o $(PROGRAM2) $(DMALLOC_LIB) 36 | 37 | mem_check: 38 | @if [ -e makefile.txt ] ; then \ 39 | echo "Using makefile.txt" ; \ 40 | $(MAKE) clean -f makefile.txt ; \ 41 | $(MAKE) $(PROGRAM) "CFLAGS=$(CFLAGS) -DDMALLOC" "DMALLOC_LIB=-ldmalloc" -f makefile.txt ; \ 42 | else \ 43 | echo "Using default makefile (i.e. no -f flag)." ; \ 44 | $(MAKE) clean ; \ 45 | $(MAKE) $(PROGRAM) "CFLAGS=$(CFLAGS) -DDMALLOC" "DMALLOC_LIB=-ldmalloc" ; \ 46 | fi 47 | ./simple_test.sh 48 | @if [ -s unfreed.txt ] ; then \ 49 | echo " " ; \ 50 | echo "Leaked some memory. See logfile for details." ;\ 51 | else \ 52 | echo " " ; \ 53 | echo "No memory leaks detected. " ;\ 54 | echo " " ; \ 55 | echo "Test passed. " ; \ 56 | echo " " ; \ 57 | fi 58 | 59 | 60 | test_red_black_tree.o: test_red_black_tree.c red_black_tree.c stack.c stack.h red_black_tree.h misc.h 61 | 62 | red_black_tree.o: red_black_tree.h stack.h red_black_tree.c stack.c misc.h misc.c 63 | 64 | stack.o: stack.c stack.h misc.h misc.c 65 | 66 | clean: 67 | rm -f *.o *~ $(PROGRAM) $(PROGRAM2) *.gcda *.gcno *.gcov unfreed.txt 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | rb_tree_demo 2 | ============ 3 | 4 | code accompanying a blog post about fuzzing a red-black tree implementation: 5 | 6 | http://blog.regehr.org/archives/896 7 | -------------------------------------------------------------------------------- /container.c: -------------------------------------------------------------------------------- 1 | #include "container.h" 2 | #include 3 | #include 4 | #include 5 | 6 | #define MAX_SIZE 10000 7 | 8 | static int size; 9 | static struct elt_t array[MAX_SIZE]; 10 | 11 | void containerCreate(void) { size = 0; } 12 | 13 | void containerInsert(int val, void *info) { 14 | assert(size < MAX_SIZE); 15 | array[size].val = val; 16 | array[size].info = info; 17 | size++; 18 | } 19 | 20 | int containerFind(int val) { 21 | int i; 22 | for (i = 0; i < size; i++) { 23 | if (array[i].val == val) 24 | return 1; 25 | } 26 | return 0; 27 | } 28 | 29 | int containerRandom(int *res) { 30 | if (size == 0) 31 | return 0; 32 | *res = array[rand() % size].val; 33 | return 1; 34 | } 35 | 36 | void containerDelete(int val) { 37 | int i, j; 38 | for (i = 0; i < size; i++) { 39 | if (array[i].val == val) 40 | goto remove; 41 | } 42 | assert(0); 43 | remove: 44 | for (j = i; j < size; j++) { 45 | array[j] = array[j + 1]; 46 | } 47 | size--; 48 | } 49 | 50 | static int compar(const void *a, const void *b) { 51 | int ai = ((struct elt_t *)a)->val; 52 | int bi = ((struct elt_t *)b)->val; 53 | return (ai > bi) - (ai < bi); 54 | } 55 | 56 | void containerSort(void) { qsort(array, size, sizeof(struct elt_t), compar); } 57 | 58 | int containerPred(int val, int *ret) { 59 | int i; 60 | containerSort(); 61 | for (i = 0; i < size; i++) { 62 | if (array[i].val == val) 63 | goto found; 64 | } 65 | return KEY_NOT_FOUND; 66 | found: 67 | if (i == 0) 68 | return NO_PRED_OR_SUCC; 69 | *ret = array[i - 1].val; 70 | return FOUND; 71 | } 72 | 73 | int containerSucc(int val, int *ret) { 74 | int i; 75 | containerSort(); 76 | for (i = 0; i < size; i++) { 77 | if (array[i].val == val) 78 | goto found; 79 | } 80 | return KEY_NOT_FOUND; 81 | found: 82 | if (i == (size - 1)) 83 | return NO_PRED_OR_SUCC; 84 | *ret = array[i + 1].val; 85 | return FOUND; 86 | } 87 | 88 | int containerStartVal(int val, int val2) { 89 | int i; 90 | containerSort(); 91 | for (i = 0; i < size; i++) { 92 | if (array[i].val >= val && array[i].val <= val2) { 93 | return i; 94 | } 95 | } 96 | return -1; 97 | } 98 | 99 | int containerNextVal(int val, int i) { 100 | i++; 101 | if (i == size) 102 | return -1; 103 | if (array[i].val <= val) 104 | return i; 105 | return -1; 106 | } 107 | 108 | int containerNext(int i) { 109 | i++; 110 | if (i == size) 111 | return -1; 112 | return i; 113 | } 114 | 115 | int containerStart(void) { 116 | containerSort(); 117 | if (size == 0) 118 | return -1; 119 | return 0; 120 | } 121 | 122 | struct elt_t containerGet(int i) { 123 | assert(i >= 0); 124 | assert(i < size); 125 | return array[i]; 126 | } 127 | 128 | void containerPrint(void) { 129 | int i; 130 | containerSort(); 131 | for (i = 0; i < size; i++) { 132 | printf("%d ", array[i].val); 133 | } 134 | printf("\n"); 135 | } 136 | -------------------------------------------------------------------------------- /container.h: -------------------------------------------------------------------------------- 1 | enum result { KEY_NOT_FOUND = 777, NO_PRED_OR_SUCC, FOUND }; 2 | 3 | struct elt_t { 4 | int val; 5 | void *info; 6 | }; 7 | 8 | void containerCreate(void); 9 | void containerInsert(int, void *); 10 | int containerFind(int); 11 | void containerDelete(int); 12 | int containerPred(int, int *); 13 | int containerSucc(int, int *); 14 | void containerPrint(void); 15 | int containerStart(void); 16 | int containerStartVal(int, int); 17 | int containerNextVal(int, int); 18 | int containerNext(int); 19 | struct elt_t containerGet(int); 20 | int containerRandom(int *); 21 | -------------------------------------------------------------------------------- /fuzz_red_black_tree.c: -------------------------------------------------------------------------------- 1 | #include "container.h" 2 | #include "red_black_tree.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #define META_REPS 1000 10 | #define FUZZ_REPS 1000 11 | 12 | /* this file has functions to test a red-black tree of integers */ 13 | 14 | void IntDest(void *a) { free((int *)a); } 15 | 16 | int IntComp(const void *a, const void *b) { 17 | if (*(int *)a > *(int *)b) 18 | return (1); 19 | if (*(int *)a < *(int *)b) 20 | return (-1); 21 | return (0); 22 | } 23 | 24 | void IntPrint(const void *a) { printf("%i", *(int *)a); } 25 | 26 | void InfoPrint(void *a) { ; } 27 | 28 | void InfoDest(void *a) { ; } 29 | 30 | int FUZZ_RANGE; 31 | 32 | int randomInt(void) { return rand() % FUZZ_RANGE; } 33 | 34 | void *randomVoidP(void) { 35 | uintptr_t p = 0; 36 | int i; 37 | for (i = 0; i < sizeof(p); i++) { 38 | p <<= 8; 39 | p |= rand() % 256; 40 | } 41 | return (void *)p; 42 | } 43 | 44 | int idx; 45 | 46 | int nodups; 47 | 48 | void InorderTreeVerify(rb_red_blk_tree *tree, rb_red_blk_node *x) { 49 | if (x != tree->nil) { 50 | struct elt_t e; 51 | InorderTreeVerify(tree, x->left); 52 | e = containerGet(idx); 53 | assert(e.val == *(int *)x->key); 54 | if (nodups) 55 | assert(e.info == x->info); 56 | idx = containerNext(idx); 57 | InorderTreeVerify(tree, x->right); 58 | } 59 | } 60 | 61 | void RBTreeVerify(rb_red_blk_tree *tree) { 62 | idx = containerStart(); 63 | InorderTreeVerify(tree, tree->root->left); 64 | assert(idx == -1); 65 | } 66 | 67 | static void fuzzit(void) { 68 | stk_stack *enumResult; 69 | int option = 0; 70 | int newKey, newKey2; 71 | int *newInt; 72 | rb_red_blk_node *newNode; 73 | rb_red_blk_tree *tree; 74 | int i; 75 | int fuzz_reps; 76 | 77 | fuzz_reps = 1 + rand() % FUZZ_REPS; 78 | 79 | tree = RBTreeCreate(IntComp, IntDest, InfoDest, IntPrint, InfoPrint); 80 | containerCreate(); 81 | nodups = rand() % 2; 82 | if (rand() % 2 == 0) { 83 | FUZZ_RANGE = 1 + rand() % fuzz_reps; 84 | } else { 85 | FUZZ_RANGE = 1 + rand() % RAND_MAX; 86 | } 87 | 88 | for (i = 0; i < fuzz_reps; i++) { 89 | 90 | checkRep(tree); 91 | 92 | again: 93 | option = 1 + rand() % 7; 94 | switch (option) { 95 | case 1: { 96 | void *p; 97 | newKey = randomInt(); 98 | 99 | if (nodups) { 100 | if (containerFind(newKey)) 101 | goto again; 102 | } 103 | 104 | newInt = (int *)malloc(sizeof(int)); 105 | *newInt = newKey; 106 | p = randomVoidP(); 107 | RBTreeInsert(tree, newInt, p); 108 | containerInsert(newKey, p); 109 | } break; 110 | 111 | case 2: { 112 | newKey = randomInt(); 113 | if ((newNode = RBExactQuery(tree, &newKey))) { 114 | assert(containerFind(newKey)); 115 | RBDelete(tree, newNode); /*assignment*/ 116 | containerDelete(newKey); 117 | } else { 118 | assert(!containerFind(newKey)); 119 | } 120 | } break; 121 | 122 | case 3: { 123 | newKey = randomInt(); 124 | if ((newNode = RBExactQuery(tree, &newKey))) { /*assignment*/ 125 | assert(containerFind(newKey)); 126 | } else { 127 | assert(!containerFind(newKey)); 128 | } 129 | } break; 130 | case 4: { 131 | int res, key2; 132 | newKey = randomInt(); 133 | res = containerPred(newKey, &key2); 134 | if ((newNode = RBExactQuery(tree, &newKey))) { /*assignment*/ 135 | newNode = TreePredecessor(tree, newNode); 136 | if (nodups) { 137 | if (tree->nil == newNode) { 138 | assert(res == NO_PRED_OR_SUCC); 139 | } else { 140 | assert(res == FOUND); 141 | assert(*(int *)newNode->key == key2); 142 | } 143 | } 144 | } else { 145 | assert(res == KEY_NOT_FOUND); 146 | } 147 | } break; 148 | case 5: { 149 | int res, key2; 150 | newKey = randomInt(); 151 | res = containerSucc(newKey, &key2); 152 | if ((newNode = RBExactQuery(tree, &newKey))) { 153 | newNode = TreeSuccessor(tree, newNode); 154 | if (nodups) { 155 | if (tree->nil == newNode) { 156 | assert(res == NO_PRED_OR_SUCC); 157 | } else { 158 | assert(res == FOUND); 159 | assert(*(int *)newNode->key == key2); 160 | } 161 | } 162 | } else { 163 | assert(!containerFind(newKey)); 164 | assert(res == KEY_NOT_FOUND); 165 | } 166 | } break; 167 | case 6: { 168 | int i; 169 | newKey = randomInt(); 170 | newKey2 = randomInt(); 171 | i = containerStartVal(newKey, newKey2); 172 | enumResult = RBEnumerate(tree, &newKey, &newKey2); 173 | while ((newNode = StackPop(enumResult))) { 174 | struct elt_t e; 175 | assert(i != -1); 176 | e = containerGet(i); 177 | assert(e.val == *(int *)newNode->key); 178 | if (nodups) 179 | assert(e.info == newNode->info); 180 | i = containerNextVal(newKey2, i); 181 | } 182 | assert(i == -1); 183 | free(enumResult); 184 | } break; 185 | case 7: { 186 | RBTreeVerify(tree); 187 | } break; 188 | default: 189 | assert(0); 190 | } 191 | } 192 | RBTreeVerify(tree); 193 | if (rand() % 2 == 0) { 194 | while (1) { 195 | int val; 196 | int res = containerRandom(&val); 197 | if (!res) 198 | break; 199 | containerDelete(val); 200 | if (!(newNode = RBExactQuery(tree, &val))) 201 | assert(0); 202 | RBDelete(tree, newNode); 203 | } 204 | } 205 | RBTreeDestroy(tree); 206 | } 207 | 208 | int main() { 209 | int i; 210 | 211 | srand(time(NULL)); 212 | 213 | for (i = 0; i < META_REPS; i++) { 214 | fuzzit(); 215 | } 216 | 217 | printf("Done fuzzing\n"); 218 | return 0; 219 | } 220 | -------------------------------------------------------------------------------- /misc.c: -------------------------------------------------------------------------------- 1 | #include "misc.h" 2 | 3 | /***********************************************************************/ 4 | /* FUNCTION: void Assert(int assertion, char* error) */ 5 | /**/ 6 | /* INPUTS: assertion should be a predicated that the programmer */ 7 | /* assumes to be true. If this assumption is not true the message */ 8 | /* error is printed and the program exits. */ 9 | /**/ 10 | /* OUTPUT: None. */ 11 | /**/ 12 | /* Modifies input: none */ 13 | /**/ 14 | /* Note: If DEBUG_ASSERT is not defined then assertions should not */ 15 | /* be in use as they will slow down the code. Therefore the */ 16 | /* compiler will complain if an assertion is used when */ 17 | /* DEBUG_ASSERT is undefined. */ 18 | /***********************************************************************/ 19 | 20 | void Assert(int assertion, char *error) { 21 | if (!assertion) { 22 | printf("Assertion Failed: %s\n", error); 23 | exit(-1); 24 | } 25 | } 26 | 27 | /***********************************************************************/ 28 | /* FUNCTION: SafeMalloc */ 29 | /**/ 30 | /* INPUTS: size is the size to malloc */ 31 | /**/ 32 | /* OUTPUT: returns pointer to allocated memory if succesful */ 33 | /**/ 34 | /* EFFECT: mallocs new memory. If malloc fails, prints error message */ 35 | /* and terminates program. */ 36 | /**/ 37 | /* Modifies Input: none */ 38 | /**/ 39 | /***********************************************************************/ 40 | 41 | void *SafeMalloc(size_t size) { 42 | void *result; 43 | 44 | if ((result = malloc(size))) { /* assignment intentional */ 45 | return (result); 46 | } else { 47 | printf("memory overflow: malloc failed in SafeMalloc."); 48 | printf(" Exiting Program.\n"); 49 | exit(-1); 50 | return (0); 51 | } 52 | } 53 | /* NullFunction does nothing it is included so that it can be passed */ 54 | /* as a function to RBTreeCreate when no other suitable function has */ 55 | /* been defined */ 56 | 57 | void NullFunction(void *junk) { ; } 58 | -------------------------------------------------------------------------------- /misc.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #ifndef INC_E_MISC_ 5 | #define INC_E_MISC_ 6 | 7 | /* CONVENTIONS: All data structures for red-black trees have the prefix */ 8 | /* "rb_" to prevent name conflicts. */ 9 | /* */ 10 | /* Function names: Each word in a function name begins with */ 11 | /* a capital letter. An example funcntion name is */ 12 | /* CreateRedTree(a,b,c). Furthermore, each function name */ 13 | /* should begin with a capital letter to easily distinguish */ 14 | /* them from variables. */ 15 | /* */ 16 | /* Variable names: Each word in a variable name begins with */ 17 | /* a capital letter EXCEPT the first letter of the variable */ 18 | /* name. For example, int newLongInt. Global variables have */ 19 | /* names beginning with "g". An example of a global */ 20 | /* variable name is gNewtonsConstant. */ 21 | 22 | void Assert(int assertion, char *error); 23 | void *SafeMalloc(size_t size); 24 | 25 | #endif 26 | -------------------------------------------------------------------------------- /red_black_tree.c: -------------------------------------------------------------------------------- 1 | #include "red_black_tree.h" 2 | #include 3 | 4 | /***********************************************************************/ 5 | /* FUNCTION: RBTreeCreate */ 6 | /**/ 7 | /* INPUTS: All the inputs are names of functions. CompFunc takes two */ 8 | /* void pointers to keys and returns 1 if the first arguement is */ 9 | /* "greater than" the second. DestFunc takes a pointer to a key and */ 10 | /* destroys it in the appropriate manner when the node containing that */ 11 | /* key is deleted. InfoDestFunc is similiar to DestFunc except it */ 12 | /* recieves a pointer to the info of a node and destroys it. */ 13 | /* PrintFunc recieves a pointer to the key of a node and prints it. */ 14 | /* PrintInfo recieves a pointer to the info of a node and prints it. */ 15 | /* If RBTreePrint is never called the print functions don't have to be */ 16 | /* defined and NullFunction can be used. */ 17 | /**/ 18 | /* OUTPUT: This function returns a pointer to the newly created */ 19 | /* red-black tree. */ 20 | /**/ 21 | /* Modifies Input: none */ 22 | /***********************************************************************/ 23 | 24 | rb_red_blk_tree *RBTreeCreate(int (*CompFunc)(const void *, const void *), 25 | void (*DestFunc)(void *), 26 | void (*InfoDestFunc)(void *), 27 | void (*PrintFunc)(const void *), 28 | void (*PrintInfo)(void *)) { 29 | rb_red_blk_tree *newTree; 30 | rb_red_blk_node *temp; 31 | 32 | newTree = (rb_red_blk_tree *)SafeMalloc(sizeof(rb_red_blk_tree)); 33 | newTree->Compare = CompFunc; 34 | newTree->DestroyKey = DestFunc; 35 | newTree->PrintKey = PrintFunc; 36 | newTree->PrintInfo = PrintInfo; 37 | newTree->DestroyInfo = InfoDestFunc; 38 | 39 | /* see the comment in the rb_red_blk_tree structure in red_black_tree.h */ 40 | /* for information on nil and root */ 41 | temp = newTree->nil = (rb_red_blk_node *)SafeMalloc(sizeof(rb_red_blk_node)); 42 | temp->parent = temp->left = temp->right = temp; 43 | temp->red = 0; 44 | temp->key = 0; 45 | temp = newTree->root = (rb_red_blk_node *)SafeMalloc(sizeof(rb_red_blk_node)); 46 | temp->parent = temp->left = temp->right = newTree->nil; 47 | temp->key = 0; 48 | temp->red = 0; 49 | return (newTree); 50 | } 51 | 52 | /***********************************************************************/ 53 | /* FUNCTION: LeftRotate */ 54 | /**/ 55 | /* INPUTS: This takes a tree so that it can access the appropriate */ 56 | /* root and nil pointers, and the node to rotate on. */ 57 | /**/ 58 | /* OUTPUT: None */ 59 | /**/ 60 | /* Modifies Input: tree, x */ 61 | /**/ 62 | /* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */ 63 | /* Cormen, Leiserson, Rivest (Chapter 14). Basically this */ 64 | /* makes the parent of x be to the left of x, x the parent of */ 65 | /* its parent before the rotation and fixes other pointers */ 66 | /* accordingly. */ 67 | /***********************************************************************/ 68 | 69 | void LeftRotate(rb_red_blk_tree *tree, rb_red_blk_node *x) { 70 | rb_red_blk_node *y; 71 | rb_red_blk_node *nil = tree->nil; 72 | 73 | /* I originally wrote this function to use the sentinel for */ 74 | /* nil to avoid checking for nil. However this introduces a */ 75 | /* very subtle bug because sometimes this function modifies */ 76 | /* the parent pointer of nil. This can be a problem if a */ 77 | /* function which calls LeftRotate also uses the nil sentinel */ 78 | /* and expects the nil sentinel's parent pointer to be unchanged */ 79 | /* after calling this function. For example, when RBDeleteFixUP */ 80 | /* calls LeftRotate it expects the parent pointer of nil to be */ 81 | /* unchanged. */ 82 | 83 | y = x->right; 84 | x->right = y->left; 85 | 86 | if (y->left != nil) 87 | y->left->parent = x; /* used to use sentinel here */ 88 | /* and do an unconditional assignment instead of testing for nil */ 89 | 90 | y->parent = x->parent; 91 | 92 | /* instead of checking if x->parent is the root as in the book, we */ 93 | /* count on the root sentinel to implicitly take care of this case */ 94 | if (x == x->parent->left) { 95 | x->parent->left = y; 96 | } else { 97 | x->parent->right = y; 98 | } 99 | y->left = x; 100 | x->parent = y; 101 | 102 | #ifdef DEBUG_ASSERT 103 | Assert(!tree->nil->red, "nil not red in LeftRotate"); 104 | #endif 105 | } 106 | 107 | /***********************************************************************/ 108 | /* FUNCTION: RightRotate */ 109 | /**/ 110 | /* INPUTS: This takes a tree so that it can access the appropriate */ 111 | /* root and nil pointers, and the node to rotate on. */ 112 | /**/ 113 | /* OUTPUT: None */ 114 | /**/ 115 | /* Modifies Input?: tree, y */ 116 | /**/ 117 | /* EFFECTS: Rotates as described in _Introduction_To_Algorithms by */ 118 | /* Cormen, Leiserson, Rivest (Chapter 14). Basically this */ 119 | /* makes the parent of x be to the left of x, x the parent of */ 120 | /* its parent before the rotation and fixes other pointers */ 121 | /* accordingly. */ 122 | /***********************************************************************/ 123 | 124 | void RightRotate(rb_red_blk_tree *tree, rb_red_blk_node *y) { 125 | rb_red_blk_node *x; 126 | rb_red_blk_node *nil = tree->nil; 127 | 128 | /* I originally wrote this function to use the sentinel for */ 129 | /* nil to avoid checking for nil. However this introduces a */ 130 | /* very subtle bug because sometimes this function modifies */ 131 | /* the parent pointer of nil. This can be a problem if a */ 132 | /* function which calls LeftRotate also uses the nil sentinel */ 133 | /* and expects the nil sentinel's parent pointer to be unchanged */ 134 | /* after calling this function. For example, when RBDeleteFixUP */ 135 | /* calls LeftRotate it expects the parent pointer of nil to be */ 136 | /* unchanged. */ 137 | 138 | x = y->left; 139 | y->left = x->right; 140 | 141 | if (nil != x->right) 142 | x->right->parent = y; /*used to use sentinel here */ 143 | /* and do an unconditional assignment instead of testing for nil */ 144 | 145 | /* instead of checking if x->parent is the root as in the book, we */ 146 | /* count on the root sentinel to implicitly take care of this case */ 147 | x->parent = y->parent; 148 | if (y == y->parent->left) { 149 | y->parent->left = x; 150 | } else { 151 | y->parent->right = x; 152 | } 153 | x->right = y; 154 | y->parent = x; 155 | 156 | #ifdef DEBUG_ASSERT 157 | Assert(!tree->nil->red, "nil not red in RightRotate"); 158 | #endif 159 | } 160 | 161 | /***********************************************************************/ 162 | /* FUNCTION: TreeInsertHelp */ 163 | /**/ 164 | /* INPUTS: tree is the tree to insert into and z is the node to insert */ 165 | /**/ 166 | /* OUTPUT: none */ 167 | /**/ 168 | /* Modifies Input: tree, z */ 169 | /**/ 170 | /* EFFECTS: Inserts z into the tree as if it were a regular binary tree */ 171 | /* using the algorithm described in _Introduction_To_Algorithms_ */ 172 | /* by Cormen et al. This funciton is only intended to be called */ 173 | /* by the RBTreeInsert function and not by the user */ 174 | /***********************************************************************/ 175 | 176 | void TreeInsertHelp(rb_red_blk_tree *tree, rb_red_blk_node *z) { 177 | /* This function should only be called by InsertRBTree (see above) */ 178 | rb_red_blk_node *x; 179 | rb_red_blk_node *y; 180 | rb_red_blk_node *nil = tree->nil; 181 | 182 | z->left = z->right = nil; 183 | y = tree->root; 184 | x = tree->root->left; 185 | while (x != nil) { 186 | y = x; 187 | if (1 == tree->Compare(x->key, z->key)) { /* x.key > z.key */ 188 | x = x->left; 189 | } else { /* x,key <= z.key */ 190 | x = x->right; 191 | } 192 | } 193 | z->parent = y; 194 | if ((y == tree->root) || 195 | (1 == tree->Compare(y->key, z->key))) { /* y.key > z.key */ 196 | y->left = z; 197 | } else { 198 | y->right = z; 199 | } 200 | 201 | #ifdef DEBUG_ASSERT 202 | Assert(!tree->nil->red, "nil not red in TreeInsertHelp"); 203 | #endif 204 | } 205 | 206 | /* Before calling Insert RBTree the node x should have its key set */ 207 | 208 | /***********************************************************************/ 209 | /* FUNCTION: RBTreeInsert */ 210 | /**/ 211 | /* INPUTS: tree is the red-black tree to insert a node which has a key */ 212 | /* pointed to by key and info pointed to by info. */ 213 | /**/ 214 | /* OUTPUT: This function returns a pointer to the newly inserted node */ 215 | /* which is guarunteed to be valid until this node is deleted. */ 216 | /* What this means is if another data structure stores this */ 217 | /* pointer then the tree does not need to be searched when this */ 218 | /* is to be deleted. */ 219 | /**/ 220 | /* Modifies Input: tree */ 221 | /**/ 222 | /* EFFECTS: Creates a node node which contains the appropriate key and */ 223 | /* info pointers and inserts it into the tree. */ 224 | /***********************************************************************/ 225 | 226 | rb_red_blk_node *RBTreeInsert(rb_red_blk_tree *tree, void *key, void *info) { 227 | rb_red_blk_node *y; 228 | rb_red_blk_node *x; 229 | rb_red_blk_node *newNode; 230 | 231 | x = (rb_red_blk_node *)SafeMalloc(sizeof(rb_red_blk_node)); 232 | x->key = key; 233 | x->info = info; 234 | 235 | TreeInsertHelp(tree, x); 236 | newNode = x; 237 | x->red = 1; 238 | while (x->parent->red) { /* use sentinel instead of checking for root */ 239 | if (x->parent == x->parent->parent->left) { 240 | y = x->parent->parent->right; 241 | if (y->red) { 242 | x->parent->red = 0; 243 | y->red = 0; 244 | x->parent->parent->red = 1; 245 | x = x->parent->parent; 246 | } else { 247 | if (x == x->parent->right) { 248 | x = x->parent; 249 | LeftRotate(tree, x); 250 | } 251 | x->parent->red = 0; 252 | x->parent->parent->red = 1; 253 | RightRotate(tree, x->parent->parent); 254 | } 255 | } else { /* case for x->parent == x->parent->parent->right */ 256 | y = x->parent->parent->left; 257 | if (y->red) { 258 | x->parent->red = 0; 259 | y->red = 0; 260 | x->parent->parent->red = 1; 261 | x = x->parent->parent; 262 | } else { 263 | if (x == x->parent->left) { 264 | x = x->parent; 265 | RightRotate(tree, x); 266 | } 267 | x->parent->red = 0; 268 | x->parent->parent->red = 1; 269 | LeftRotate(tree, x->parent->parent); 270 | } 271 | } 272 | } 273 | tree->root->left->red = 0; 274 | return (newNode); 275 | 276 | #ifdef DEBUG_ASSERT 277 | Assert(!tree->nil->red, "nil not red in RBTreeInsert"); 278 | Assert(!tree->root->red, "root not red in RBTreeInsert"); 279 | #endif 280 | } 281 | 282 | /***********************************************************************/ 283 | /* FUNCTION: TreeSuccessor */ 284 | /**/ 285 | /* INPUTS: tree is the tree in question, and x is the node we want the */ 286 | /* the successor of. */ 287 | /**/ 288 | /* OUTPUT: This function returns the successor of x or NULL if no */ 289 | /* successor exists. */ 290 | /**/ 291 | /* Modifies Input: none */ 292 | /**/ 293 | /* Note: uses the algorithm in _Introduction_To_Algorithms_ */ 294 | /***********************************************************************/ 295 | 296 | rb_red_blk_node *TreeSuccessor(rb_red_blk_tree *tree, rb_red_blk_node *x) { 297 | rb_red_blk_node *y; 298 | rb_red_blk_node *nil = tree->nil; 299 | rb_red_blk_node *root = tree->root; 300 | 301 | if (nil != (y = x->right)) { /* assignment to y is intentional */ 302 | while (y->left != nil) { /* returns the minium of the right subtree of x */ 303 | y = y->left; 304 | } 305 | return (y); 306 | } else { 307 | y = x->parent; 308 | while (x == y->right) { /* sentinel used instead of checking for nil */ 309 | x = y; 310 | y = y->parent; 311 | } 312 | if (y == root) 313 | return (nil); 314 | return (y); 315 | } 316 | } 317 | 318 | /***********************************************************************/ 319 | /* FUNCTION: Treepredecessor */ 320 | /**/ 321 | /* INPUTS: tree is the tree in question, and x is the node we want the */ 322 | /* the predecessor of. */ 323 | /**/ 324 | /* OUTPUT: This function returns the predecessor of x or NULL if no */ 325 | /* predecessor exists. */ 326 | /**/ 327 | /* Modifies Input: none */ 328 | /**/ 329 | /* Note: uses the algorithm in _Introduction_To_Algorithms_ */ 330 | /***********************************************************************/ 331 | 332 | rb_red_blk_node *TreePredecessor(rb_red_blk_tree *tree, rb_red_blk_node *x) { 333 | rb_red_blk_node *y; 334 | rb_red_blk_node *nil = tree->nil; 335 | rb_red_blk_node *root = tree->root; 336 | 337 | if (nil != (y = x->left)) { /* assignment to y is intentional */ 338 | while (y->right != nil) { /* returns the maximum of the left subtree of x */ 339 | y = y->right; 340 | } 341 | return (y); 342 | } else { 343 | y = x->parent; 344 | while (x == y->left) { 345 | if (y == root) 346 | return (nil); 347 | x = y; 348 | y = y->parent; 349 | } 350 | return (y); 351 | } 352 | } 353 | 354 | /***********************************************************************/ 355 | /* FUNCTION: InorderTreePrint */ 356 | /**/ 357 | /* INPUTS: tree is the tree to print and x is the current inorder node */ 358 | /**/ 359 | /* OUTPUT: none */ 360 | /**/ 361 | /* EFFECTS: This function recursively prints the nodes of the tree */ 362 | /* inorder using the PrintKey and PrintInfo functions. */ 363 | /**/ 364 | /* Modifies Input: none */ 365 | /**/ 366 | /* Note: This function should only be called from RBTreePrint */ 367 | /***********************************************************************/ 368 | 369 | void InorderTreePrint(rb_red_blk_tree *tree, rb_red_blk_node *x) { 370 | rb_red_blk_node *nil = tree->nil; 371 | rb_red_blk_node *root = tree->root; 372 | if (x != tree->nil) { 373 | InorderTreePrint(tree, x->left); 374 | printf("info="); 375 | tree->PrintInfo(x->info); 376 | printf(" key="); 377 | tree->PrintKey(x->key); 378 | printf(" l->key="); 379 | if (x->left == nil) 380 | printf("NULL"); 381 | else 382 | tree->PrintKey(x->left->key); 383 | printf(" r->key="); 384 | if (x->right == nil) 385 | printf("NULL"); 386 | else 387 | tree->PrintKey(x->right->key); 388 | printf(" p->key="); 389 | if (x->parent == root) 390 | printf("NULL"); 391 | else 392 | tree->PrintKey(x->parent->key); 393 | printf(" red=%i\n", x->red); 394 | InorderTreePrint(tree, x->right); 395 | } 396 | } 397 | 398 | /***********************************************************************/ 399 | /* FUNCTION: TreeDestHelper */ 400 | /**/ 401 | /* INPUTS: tree is the tree to destroy and x is the current node */ 402 | /**/ 403 | /* OUTPUT: none */ 404 | /**/ 405 | /* EFFECTS: This function recursively destroys the nodes of the tree */ 406 | /* postorder using the DestroyKey and DestroyInfo functions. */ 407 | /**/ 408 | /* Modifies Input: tree, x */ 409 | /**/ 410 | /* Note: This function should only be called by RBTreeDestroy */ 411 | /***********************************************************************/ 412 | 413 | void TreeDestHelper(rb_red_blk_tree *tree, rb_red_blk_node *x) { 414 | rb_red_blk_node *nil = tree->nil; 415 | if (x != nil) { 416 | TreeDestHelper(tree, x->left); 417 | TreeDestHelper(tree, x->right); 418 | tree->DestroyKey(x->key); 419 | tree->DestroyInfo(x->info); 420 | free(x); 421 | } 422 | } 423 | 424 | /***********************************************************************/ 425 | /* FUNCTION: RBTreeDestroy */ 426 | /**/ 427 | /* INPUTS: tree is the tree to destroy */ 428 | /**/ 429 | /* OUTPUT: none */ 430 | /**/ 431 | /* EFFECT: Destroys the key and frees memory */ 432 | /**/ 433 | /* Modifies Input: tree */ 434 | /**/ 435 | /***********************************************************************/ 436 | 437 | void RBTreeDestroy(rb_red_blk_tree *tree) { 438 | TreeDestHelper(tree, tree->root->left); 439 | free(tree->root); 440 | free(tree->nil); 441 | free(tree); 442 | } 443 | 444 | /***********************************************************************/ 445 | /* FUNCTION: RBTreePrint */ 446 | /**/ 447 | /* INPUTS: tree is the tree to print */ 448 | /**/ 449 | /* OUTPUT: none */ 450 | /**/ 451 | /* EFFECT: This function recursively prints the nodes of the tree */ 452 | /* inorder using the PrintKey and PrintInfo functions. */ 453 | /**/ 454 | /* Modifies Input: none */ 455 | /**/ 456 | /***********************************************************************/ 457 | 458 | void RBTreePrint(rb_red_blk_tree *tree) { 459 | InorderTreePrint(tree, tree->root->left); 460 | } 461 | 462 | /***********************************************************************/ 463 | /* FUNCTION: RBExactQuery */ 464 | /**/ 465 | /* INPUTS: tree is the tree to print and q is a pointer to the key */ 466 | /* we are searching for */ 467 | /**/ 468 | /* OUTPUT: returns the a node with key equal to q. If there are */ 469 | /* multiple nodes with key equal to q this function returns */ 470 | /* the one highest in the tree */ 471 | /**/ 472 | /* Modifies Input: none */ 473 | /**/ 474 | /***********************************************************************/ 475 | 476 | rb_red_blk_node *RBExactQuery(rb_red_blk_tree *tree, void *q) { 477 | rb_red_blk_node *x = tree->root->left; 478 | rb_red_blk_node *nil = tree->nil; 479 | int compVal; 480 | if (x == nil) 481 | return (0); 482 | compVal = tree->Compare(x->key, (int *)q); 483 | while (0 != compVal) { /*assignemnt*/ 484 | if (1 == compVal) { /* x->key > q */ 485 | x = x->left; 486 | } else { 487 | x = x->right; 488 | } 489 | if (x == nil) 490 | return (0); 491 | compVal = tree->Compare(x->key, (int *)q); 492 | } 493 | return (x); 494 | } 495 | 496 | /***********************************************************************/ 497 | /* FUNCTION: RBDeleteFixUp */ 498 | /**/ 499 | /* INPUTS: tree is the tree to fix and x is the child of the spliced */ 500 | /* out node in RBTreeDelete. */ 501 | /**/ 502 | /* OUTPUT: none */ 503 | /**/ 504 | /* EFFECT: Performs rotations and changes colors to restore red-black */ 505 | /* properties after a node is deleted */ 506 | /**/ 507 | /* Modifies Input: tree, x */ 508 | /**/ 509 | /* The algorithm from this function is from _Introduction_To_Algorithms_ */ 510 | /***********************************************************************/ 511 | 512 | void RBDeleteFixUp(rb_red_blk_tree *tree, rb_red_blk_node *x) { 513 | rb_red_blk_node *root = tree->root->left; 514 | rb_red_blk_node *w; 515 | 516 | while ((!x->red) && (root != x)) { 517 | if (x == x->parent->left) { 518 | w = x->parent->right; 519 | if (w->red) { 520 | w->red = 0; 521 | x->parent->red = 1; 522 | LeftRotate(tree, x->parent); 523 | w = x->parent->right; 524 | } 525 | if ((!w->right->red) && (!w->left->red)) { 526 | w->red = 1; 527 | x = x->parent; 528 | } else { 529 | if (!w->right->red) { 530 | w->left->red = 0; 531 | w->red = 1; 532 | RightRotate(tree, w); 533 | w = x->parent->right; 534 | } 535 | w->red = x->parent->red; 536 | x->parent->red = 0; 537 | w->right->red = 0; 538 | LeftRotate(tree, x->parent); 539 | x = root; /* this is to exit while loop */ 540 | } 541 | } else { /* the code below is has left and right switched from above */ 542 | w = x->parent->left; 543 | if (w->red) { 544 | w->red = 0; 545 | x->parent->red = 1; 546 | RightRotate(tree, x->parent); 547 | w = x->parent->left; 548 | } 549 | if ((!w->right->red) && (!w->left->red)) { 550 | w->red = 1; 551 | x = x->parent; 552 | } else { 553 | if (!w->left->red) { 554 | w->right->red = 0; 555 | w->red = 1; 556 | LeftRotate(tree, w); 557 | w = x->parent->left; 558 | } 559 | w->red = x->parent->red; 560 | x->parent->red = 0; 561 | w->left->red = 0; 562 | RightRotate(tree, x->parent); 563 | x = root; /* this is to exit while loop */ 564 | } 565 | } 566 | } 567 | x->red = 0; 568 | 569 | #ifdef DEBUG_ASSERT 570 | Assert(!tree->nil->red, "nil not black in RBDeleteFixUp"); 571 | #endif 572 | } 573 | 574 | /***********************************************************************/ 575 | /* FUNCTION: RBDelete */ 576 | /**/ 577 | /* INPUTS: tree is the tree to delete node z from */ 578 | /**/ 579 | /* OUTPUT: none */ 580 | /**/ 581 | /* EFFECT: Deletes z from tree and frees the key and info of z */ 582 | /* using DestoryKey and DestoryInfo. Then calls */ 583 | /* RBDeleteFixUp to restore red-black properties */ 584 | /**/ 585 | /* Modifies Input: tree, z */ 586 | /**/ 587 | /* The algorithm from this function is from _Introduction_To_Algorithms_ */ 588 | /***********************************************************************/ 589 | 590 | void RBDelete(rb_red_blk_tree *tree, rb_red_blk_node *z) { 591 | rb_red_blk_node *y; 592 | rb_red_blk_node *x; 593 | rb_red_blk_node *nil = tree->nil; 594 | rb_red_blk_node *root = tree->root; 595 | 596 | y = ((z->left == nil) || (z->right == nil)) ? z : TreeSuccessor(tree, z); 597 | x = (y->left == nil) ? y->right : y->left; 598 | if (root == 599 | (x->parent = y->parent)) { /* assignment of y->p to x->p is intentional */ 600 | root->left = x; 601 | } else { 602 | if (y == y->parent->left) { 603 | y->parent->left = x; 604 | } else { 605 | y->parent->right = x; 606 | } 607 | } 608 | if (y != z) { /* y should not be nil in this case */ 609 | 610 | #ifdef DEBUG_ASSERT 611 | Assert((y != tree->nil), "y is nil in RBDelete\n"); 612 | #endif 613 | /* y is the node to splice out and x is its child */ 614 | 615 | if (!(y->red)) 616 | RBDeleteFixUp(tree, x); 617 | 618 | tree->DestroyKey(z->key); 619 | tree->DestroyInfo(z->info); 620 | y->left = z->left; 621 | y->right = z->right; 622 | y->parent = z->parent; 623 | y->red = z->red; 624 | z->left->parent = z->right->parent = y; 625 | if (z == z->parent->left) { 626 | z->parent->left = y; 627 | } else { 628 | z->parent->right = y; 629 | } 630 | free(z); 631 | } else { 632 | tree->DestroyKey(y->key); 633 | tree->DestroyInfo(y->info); 634 | if (!(y->red)) 635 | RBDeleteFixUp(tree, x); 636 | free(y); 637 | } 638 | 639 | #ifdef DEBUG_ASSERT 640 | Assert(!tree->nil->red, "nil not black in RBDelete"); 641 | #endif 642 | } 643 | 644 | /***********************************************************************/ 645 | /* FUNCTION: RBEnumerate */ 646 | /**/ 647 | /* INPUTS: tree is the tree to look for keys >= low */ 648 | /* and <= high with respect to the Compare function */ 649 | /**/ 650 | /* OUTPUT: stack containing pointers to the nodes between [low,high] */ 651 | /**/ 652 | /* Modifies Input: none */ 653 | /***********************************************************************/ 654 | 655 | stk_stack *RBEnumerate(rb_red_blk_tree *tree, void *low, void *high) { 656 | stk_stack *enumResultStack; 657 | rb_red_blk_node *nil = tree->nil; 658 | rb_red_blk_node *x = tree->root->left; 659 | rb_red_blk_node *lastBest = nil; 660 | 661 | enumResultStack = StackCreate(); 662 | while (nil != x) { 663 | if (1 == (tree->Compare(x->key, high))) { /* x->key > high */ 664 | x = x->left; 665 | } else { 666 | lastBest = x; 667 | x = x->right; 668 | } 669 | } 670 | while ((lastBest != nil) && (1 != tree->Compare(low, lastBest->key))) { 671 | StackPush(enumResultStack, lastBest); 672 | lastBest = TreePredecessor(tree, lastBest); 673 | } 674 | return (enumResultStack); 675 | } 676 | 677 | int checkRepHelper(rb_red_blk_node *node, rb_red_blk_tree *t) { 678 | int left_black_cnt, right_black_cnt; 679 | 680 | /* by convention sentinel nodes point to nil instead of null */ 681 | assert(node); 682 | if (node == t->nil) 683 | return 0; 684 | 685 | /* the tree order must be respected */ 686 | /* parents and children must point to each other */ 687 | if (node->left != t->nil) { 688 | int tmp = t->Compare(node->key, node->left->key); 689 | assert(tmp == 0 || tmp == 1); 690 | assert(node->left->parent == node); 691 | } 692 | if (node->right != t->nil) { 693 | int tmp = t->Compare(node->key, node->right->key); 694 | assert(tmp == 0 || tmp == -1); 695 | assert(node->right->parent == node); 696 | } 697 | if (node->left != t->nil && node->right != t->nil) { 698 | int tmp = t->Compare(node->left->key, node->right->key); 699 | assert(tmp == 0 || tmp == -1); 700 | } 701 | 702 | /* both children of a red node are black */ 703 | if (node->red) { 704 | assert(!node->left->red); 705 | assert(!node->right->red); 706 | } 707 | 708 | /* every root->leaf path has the same number of black nodes */ 709 | left_black_cnt = checkRepHelper(node->left, t); 710 | right_black_cnt = checkRepHelper(node->right, t); 711 | assert(left_black_cnt == right_black_cnt); 712 | return left_black_cnt + (node->red ? 0 : 1); 713 | } 714 | 715 | void checkRep(rb_red_blk_tree *tree) { 716 | /* root is black by convention */ 717 | assert(!tree->root->left->red); 718 | checkRepHelper(tree->root->left, tree); 719 | } 720 | -------------------------------------------------------------------------------- /red_black_tree.h: -------------------------------------------------------------------------------- 1 | #ifdef DMALLOC 2 | #include 3 | #endif 4 | #include "misc.h" 5 | #include "stack.h" 6 | 7 | /* CONVENTIONS: All data structures for red-black trees have the prefix */ 8 | /* "rb_" to prevent name conflicts. */ 9 | /* */ 10 | /* Function names: Each word in a function name begins with */ 11 | /* a capital letter. An example funcntion name is */ 12 | /* CreateRedTree(a,b,c). Furthermore, each function name */ 13 | /* should begin with a capital letter to easily distinguish */ 14 | /* them from variables. */ 15 | /* */ 16 | /* Variable names: Each word in a variable name begins with */ 17 | /* a capital letter EXCEPT the first letter of the variable */ 18 | /* name. For example, int newLongInt. Global variables have */ 19 | /* names beginning with "g". An example of a global */ 20 | /* variable name is gNewtonsConstant. */ 21 | 22 | /* comment out the line below to remove all the debugging assertion */ 23 | /* checks from the compiled code. */ 24 | #define DEBUG_ASSERT 1 25 | 26 | typedef struct rb_red_blk_node { 27 | void *key; 28 | void *info; 29 | int red; /* if red=0 then the node is black */ 30 | struct rb_red_blk_node *left; 31 | struct rb_red_blk_node *right; 32 | struct rb_red_blk_node *parent; 33 | } rb_red_blk_node; 34 | 35 | /* Compare(a,b) should return 1 if *a > *b, -1 if *a < *b, and 0 otherwise */ 36 | /* Destroy(a) takes a pointer to whatever key might be and frees it accordingly 37 | */ 38 | typedef struct rb_red_blk_tree { 39 | int (*Compare)(const void *a, const void *b); 40 | void (*DestroyKey)(void *a); 41 | void (*DestroyInfo)(void *a); 42 | void (*PrintKey)(const void *a); 43 | void (*PrintInfo)(void *a); 44 | /* A sentinel is used for root and for nil. These sentinels are */ 45 | /* created when RBTreeCreate is caled. root->left should always */ 46 | /* point to the node which is the root of the tree. nil points to a */ 47 | /* node which should always be black but has aribtrary children and */ 48 | /* parent and no key or info. The point of using these sentinels is so */ 49 | /* that the root and nil nodes do not require special cases in the code */ 50 | rb_red_blk_node *root; 51 | rb_red_blk_node *nil; 52 | } rb_red_blk_tree; 53 | 54 | rb_red_blk_tree *RBTreeCreate(int (*CompFunc)(const void *, const void *), 55 | void (*DestFunc)(void *), 56 | void (*InfoDestFunc)(void *), 57 | void (*PrintFunc)(const void *), 58 | void (*PrintInfo)(void *)); 59 | rb_red_blk_node *RBTreeInsert(rb_red_blk_tree *, void *key, void *info); 60 | void RBTreePrint(rb_red_blk_tree *); 61 | void RBDelete(rb_red_blk_tree *, rb_red_blk_node *); 62 | void RBTreeDestroy(rb_red_blk_tree *); 63 | rb_red_blk_node *TreePredecessor(rb_red_blk_tree *, rb_red_blk_node *); 64 | rb_red_blk_node *TreeSuccessor(rb_red_blk_tree *, rb_red_blk_node *); 65 | rb_red_blk_node *RBExactQuery(rb_red_blk_tree *, void *); 66 | stk_stack *RBEnumerate(rb_red_blk_tree *tree, void *low, void *high); 67 | void NullFunction(void *); 68 | void checkRep(rb_red_blk_tree *tree); 69 | -------------------------------------------------------------------------------- /simple_test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | eval `dmalloc -l logfile -i 100 high` 3 | ./test_rb<tail) { 5 | free(stack1); 6 | return (stack2); 7 | } else { 8 | stack1->tail->next = stack2->top; 9 | stack1->tail = stack2->tail; 10 | free(stack2); 11 | return (stack1); 12 | } 13 | } 14 | 15 | stk_stack *StackCreate() { 16 | stk_stack *newStack; 17 | 18 | newStack = (stk_stack *)SafeMalloc(sizeof(stk_stack)); 19 | newStack->top = newStack->tail = NULL; 20 | return (newStack); 21 | } 22 | 23 | void StackPush(stk_stack *theStack, DATA_TYPE newInfoPointer) { 24 | stk_stack_node *newNode; 25 | 26 | if (!theStack->top) { 27 | newNode = (stk_stack_node *)SafeMalloc(sizeof(stk_stack_node)); 28 | newNode->info = newInfoPointer; 29 | newNode->next = theStack->top; 30 | theStack->top = newNode; 31 | theStack->tail = newNode; 32 | } else { 33 | newNode = (stk_stack_node *)SafeMalloc(sizeof(stk_stack_node)); 34 | newNode->info = newInfoPointer; 35 | newNode->next = theStack->top; 36 | theStack->top = newNode; 37 | } 38 | } 39 | 40 | DATA_TYPE StackPop(stk_stack *theStack) { 41 | DATA_TYPE popInfo; 42 | stk_stack_node *oldNode; 43 | 44 | if (theStack->top) { 45 | popInfo = theStack->top->info; 46 | oldNode = theStack->top; 47 | theStack->top = theStack->top->next; 48 | free(oldNode); 49 | if (!theStack->top) 50 | theStack->tail = NULL; 51 | } else { 52 | popInfo = NULL; 53 | } 54 | return (popInfo); 55 | } 56 | 57 | void StackDestroy(stk_stack *theStack, void DestFunc(void *a)) { 58 | stk_stack_node *x = theStack->top; 59 | stk_stack_node *y; 60 | 61 | if (theStack) { 62 | while (x) { 63 | y = x->next; 64 | DestFunc(x->info); 65 | free(x); 66 | x = y; 67 | } 68 | free(theStack); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /stack.h: -------------------------------------------------------------------------------- 1 | #include "misc.h" 2 | 3 | /* CONVENTIONS: All data structures for stacks have the prefix */ 4 | /* "stk_" to prevent name conflicts. */ 5 | /* */ 6 | /* Function names: Each word in a function name begins with */ 7 | /* a capital letter. An example funcntion name is */ 8 | /* CreateRedTree(a,b,c). Furthermore, each function name */ 9 | /* should begin with a capital letter to easily distinguish */ 10 | /* them from variables. */ 11 | /* */ 12 | /* Variable names: Each word in a variable name begins with */ 13 | /* a capital letter EXCEPT the first letter of the variable */ 14 | /* name. For example, int newLongInt. Global variables have */ 15 | /* names beginning with "g". An example of a global */ 16 | /* variable name is gNewtonsConstant. */ 17 | 18 | /* if DATA_TYPE is undefined then stack.h and stack.c will be code for */ 19 | /* stacks of void *, if they are defined then they will be stacks of the */ 20 | /* appropriate data_type */ 21 | 22 | #ifndef DATA_TYPE 23 | #define DATA_TYPE void * 24 | #endif 25 | 26 | typedef struct stk_stack_node { 27 | DATA_TYPE info; 28 | struct stk_stack_node *next; 29 | } stk_stack_node; 30 | 31 | typedef struct stk_stack { 32 | stk_stack_node *top; 33 | stk_stack_node *tail; 34 | } stk_stack; 35 | 36 | /* These functions are all very straightforward and self-commenting so */ 37 | /* I didn't think additional comments would be useful */ 38 | stk_stack *StackJoin(stk_stack *stack1, stk_stack *stack2); 39 | stk_stack *StackCreate(); 40 | void StackPush(stk_stack *theStack, DATA_TYPE newInfoPointer); 41 | void *StackPop(stk_stack *theStack); 42 | -------------------------------------------------------------------------------- /test_red_black_tree.c: -------------------------------------------------------------------------------- 1 | #include "red_black_tree.h" 2 | #include 3 | #include 4 | 5 | /* this file has functions to test a red-black tree of integers */ 6 | 7 | void IntDest(void *a) { free((int *)a); } 8 | 9 | int IntComp(const void *a, const void *b) { 10 | if (*(int *)a > *(int *)b) 11 | return (1); 12 | if (*(int *)a < *(int *)b) 13 | return (-1); 14 | return (0); 15 | } 16 | 17 | void IntPrint(const void *a) { printf("%i", *(int *)a); } 18 | 19 | void InfoPrint(void *a) { ; } 20 | 21 | void InfoDest(void *a) { ; } 22 | 23 | int main() { 24 | stk_stack *enumResult; 25 | int option = 0; 26 | int newKey, newKey2; 27 | int *newInt; 28 | rb_red_blk_node *newNode; 29 | rb_red_blk_tree *tree; 30 | 31 | tree = RBTreeCreate(IntComp, IntDest, InfoDest, IntPrint, InfoPrint); 32 | while (option != 8) { 33 | printf("choose one of the following:\n"); 34 | printf("(1) add to tree\n(2) delete from tree\n(3) query\n"); 35 | printf("(4) find predecessor\n(5) find sucessor\n(6) enumerate\n"); 36 | printf("(7) print tree\n(8) quit\n"); 37 | do 38 | option = fgetc(stdin); 39 | while (-1 != option && isspace(option)); 40 | option -= '0'; 41 | switch (option) { 42 | case 1: { 43 | printf("type key for new node\n"); 44 | scanf("%i", &newKey); 45 | newInt = (int *)malloc(sizeof(int)); 46 | *newInt = newKey; 47 | RBTreeInsert(tree, newInt, 0); 48 | } break; 49 | 50 | case 2: { 51 | printf("type key of node to remove\n"); 52 | scanf("%i", &newKey); 53 | if ((newNode = RBExactQuery(tree, &newKey))) 54 | RBDelete(tree, newNode); /*assignment*/ 55 | else 56 | printf("key not found in tree, no action taken\n"); 57 | } break; 58 | 59 | case 3: { 60 | printf("type key of node to query for\n"); 61 | scanf("%i", &newKey); 62 | if ((newNode = RBExactQuery(tree, &newKey))) { /*assignment*/ 63 | printf("data found in tree at location %p\n", (void *)newNode); 64 | } else { 65 | printf("data not in tree\n"); 66 | } 67 | } break; 68 | case 4: { 69 | printf("type key of node to find predecessor of\n"); 70 | scanf("%i", &newKey); 71 | if ((newNode = RBExactQuery(tree, &newKey))) { /*assignment*/ 72 | newNode = TreePredecessor(tree, newNode); 73 | if (tree->nil == newNode) { 74 | printf("there is no predecessor for that node (it is a minimum)\n"); 75 | } else { 76 | printf("predecessor has key %i\n", *(int *)newNode->key); 77 | } 78 | } else { 79 | printf("data not in tree\n"); 80 | } 81 | } break; 82 | case 5: { 83 | printf("type key of node to find successor of\n"); 84 | scanf("%i", &newKey); 85 | if ((newNode = RBExactQuery(tree, &newKey))) { 86 | newNode = TreeSuccessor(tree, newNode); 87 | if (tree->nil == newNode) { 88 | printf("there is no successor for that node (it is a maximum)\n"); 89 | } else { 90 | printf("successor has key %i\n", *(int *)newNode->key); 91 | } 92 | } else { 93 | printf("data not in tree\n"); 94 | } 95 | } break; 96 | case 6: { 97 | printf("type low and high keys to see all keys between them\n"); 98 | scanf("%i %i", &newKey, &newKey2); 99 | enumResult = RBEnumerate(tree, &newKey, &newKey2); 100 | while ((newNode = StackPop(enumResult))) { 101 | tree->PrintKey(newNode->key); 102 | printf("\n"); 103 | } 104 | free(enumResult); 105 | } break; 106 | case 7: { 107 | RBTreePrint(tree); 108 | } break; 109 | case 8: { 110 | RBTreeDestroy(tree); 111 | return 0; 112 | } break; 113 | default: 114 | printf("Invalid input; Please try again.\n"); 115 | } 116 | } 117 | return 0; 118 | } 119 | --------------------------------------------------------------------------------