2 * Bacula red-black binary tree routines.
4 * btree is a binary tree with the links being in the data item.
6 * Developped in part from ideas obtained from several online University
9 * Kern Sibbald, November MMV
15 Copyright (C) 2005 Kern Sibbald
17 This program is free software; you can redistribute it and/or
18 modify it under the terms of the GNU General Public License
19 version 2 as amended with additional clauses defined in the
20 file LICENSE in the main source directory.
22 This program is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 the file LICENSE for additional details.
32 /* ===================================================================
37 * Insert an item in the tree, but only if it is unique
38 * otherwise, the item is returned non inserted
39 * The big trick is keeping the tree balanced after the
40 * insert. We use a parent pointer to make it simpler and
43 * Returns: item if item inserted
44 * other_item if same value already exists (item not inserted)
46 bnode *btree::insert(bnode *item, int compare(bnode *item1, bnode *item2))
49 bnode *last = NULL; /* last leaf if not found */
57 comp = compare(item, x);
60 } else if (comp > 0) {
67 if (found) { /* found? */
68 return found; /* yes, return item found */
70 /* Handle empty tree */
77 /* Not found, so insert it on appropriate side of tree */
87 /* Now we must walk up the tree balancing it */
89 while (x != head && x->parent->red) {
90 if (x->parent == x->parent->parent->left) {
91 /* Look at the right side of our grandparent */
92 y = x->parent->parent->right;
94 /* our parent must be black */
95 x->parent->red = false;
97 x->parent->parent->red = true;
98 x = x->parent->parent; /* move up to grandpa */
100 if (x == x->parent->right) { /* right side of parent? */
104 /* make parent black too */
105 x->parent->red = false;
106 x->parent->parent->red = true;
107 right_rotate(x->parent->parent);
110 /* Look at left side of our grandparent */
111 y = x->parent->parent->left;
113 x->parent->red = false;
115 x->parent->parent->red = true;
116 x = x->parent->parent; /* move up to grandpa */
118 if (x == x->parent->left) {
122 /* make parent black too */
123 x->parent->red = false;
124 x->parent->parent->red = true;
125 left_rotate(x->parent->parent);
129 /* Make sure the head is always black */
138 bnode *btree::search(bnode *item, int compare(bnode *item1, bnode *item2))
145 while (x && !found) {
146 comp = compare(item, x);
149 } else if (comp > 0) {
159 * Get first item (i.e. lowest value)
161 bnode *btree::first(void)
179 * This is a non-recursive btree walk routine that returns
180 * the items one at a time in order. I've never seen a
181 * non-recursive tree walk routine published that returns
182 * one item at a time rather than doing a callback.
184 * Return the next item in sorted order. We assume first()
185 * was called once before calling this routine.
186 * We always go down as far as we can to the left, then up, and
187 * down one to the right, and again down as far as we can to the
190 * Returns: pointer to next larger item
191 * NULL when no more items in tree
193 bnode *btree::next(bnode *item)
198 if ((down && !x->left && x->right) || (!down && x->right)) {
199 /* Move down to right one */
202 /* Then all the way down left */
209 /* We have gone down all we can, so now go up */
211 /* If at head, we are done */
215 /* Move up in tree */
217 /* if coming from right, continue up */
218 if (x->parent->right == x) {
222 /* Coming from left, go up one -- ie. return parent */
228 * Similer to next(), but visits all right nodes when
229 * coming up the tree.
231 bnode *btree::any(bnode *item)
236 if ((down && !x->left && x->right) || (!down && x->right)) {
237 /* Move down to right one */
240 /* Then all the way down left */
247 /* We have gone down all we can, so now go up */
249 /* If at head, we are done */
253 /* Move up in tree */
255 /* Go up one and return parent */
261 /* x is item, y is below and to right, then rotated to below left */
262 void btree::left_rotate(bnode *item)
273 y->parent = x->parent;
274 /* if no parent then we have a new head */
277 } else if (x == x->parent->left) {
280 x->parent->right = y;
286 void btree::right_rotate(bnode *item)
294 x->right->parent = y;
296 x->parent = y->parent;
297 /* if no parent then we have a new head */
300 } else if (y == y->parent->left) {
303 y->parent->right = x;
310 void btree::remove(bnode *item)
314 /* Destroy the tree contents. Not totally working */
315 void btree::destroy()
319 for (x=first(); (y=any(x)); ) {
320 /* Prune the last item */
323 } else if (x == x->parent->left) {
324 x->parent->left = NULL;
325 } else if (x == x->parent->right) {
326 x->parent->right = NULL;
328 if (!x->left && !x->right) {
329 free((void *)x); /* free previous node */
331 x = y; /* save last node */
353 static int my_compare(bnode *item1, bnode *item2)
357 jcr1 = (MYJCR *)item1;
358 jcr2 = (MYJCR *)item2;
359 comp = strcmp(jcr1->buf, jcr2->buf);
360 //Dmsg3(000, "compare=%d: %s to %s\n", comp, jcr1->buf, jcr2->buf);
372 /* Now do a binary insert for the tree */
373 jcr_chain = New(btree());
375 printf("append %d items\n", CNT*CNT*CNT);
378 for (int i=0; i<CNT; i++) {
379 for (int j=0; j<CNT; j++) {
380 for (int k=0; k<CNT; k++) {
382 if ((count & 0x3FF) == 0) {
383 Dmsg1(000, "At %d\n", count);
385 jcr = (MYJCR *)malloc(sizeof(MYJCR));
386 memset(jcr, 0, sizeof(MYJCR));
387 jcr->buf = bstrdup(buf);
388 jcr1 = (MYJCR *)jcr_chain->insert((bnode *)jcr, my_compare);
390 Dmsg2(000, "Insert of %s vs %s failed.\n", jcr->buf, jcr1->buf);
400 printf("%d items appended\n", CNT*CNT*CNT);
401 jcr = (MYJCR *)malloc(sizeof(MYJCR));
402 memset(jcr, 0, sizeof(MYJCR));
404 jcr->buf = bstrdup(buf);
405 if (jcr_chain->search((bnode *)jcr, my_compare)) {
406 printf("One less failed!!!!\n");
408 printf("One less: OK\n");
411 strcpy(buf, "ZZZZZZZZZZZZZZZZ");
412 jcr->buf = bstrdup(buf);
413 if (jcr_chain->search((bnode *)jcr, my_compare)) {
414 printf("One greater failed!!!!\n");
416 printf("One greater: OK\n");
420 jcr->buf = bstrdup(buf);
421 if (jcr_chain->search((bnode *)jcr, my_compare)) {
422 printf("Search for AAA failed!!!!\n");
428 jcr->buf = bstrdup(buf);
429 if (jcr_chain->search((bnode *)jcr, my_compare)) {
430 printf("Search for ZZZ failed!!!!\n");
439 printf("Find each of %d items in tree.\n", count);
440 for (jcr=(MYJCR *)jcr_chain->first(); (jcr=(MYJCR *)jcr_chain->next((bnode *)jcr)); ) {
441 // printf("Got: %s\n", jcr->buf);
442 if (!jcr_chain->search((bnode *)jcr, my_compare)) {
443 printf("btree binary_search item not found = %s\n", jcr->buf);
446 printf("Free each of %d items in tree.\n", count);
447 for (jcr=(MYJCR *)jcr_chain->first(); (jcr=(MYJCR *)jcr_chain->next((bnode *)jcr)); ) {