📄 tree234.c
字号:
/* * Find an element e in a sorted 2-3-4 tree t. Returns NULL if not * found. e is always passed as the first argument to cmp, so cmp * can be an asymmetric function if desired. cmp can also be passed * as NULL, in which case the compare function from the tree proper * will be used. */void *findrelpos234(tree234 *t, void *e, cmpfn234 cmp, int relation, int *index) { node234 *n; void *ret; int c; int idx, ecount, kcount, cmpret; if (t->root == NULL) return NULL; if (cmp == NULL) cmp = t->cmp; n = t->root; /* * Attempt to find the element itself. */ idx = 0; ecount = -1; /* * Prepare a fake `cmp' result if e is NULL. */ cmpret = 0; if (e == NULL) { assert(relation == REL234_LT || relation == REL234_GT); if (relation == REL234_LT) cmpret = +1; /* e is a max: always greater */ else if (relation == REL234_GT) cmpret = -1; /* e is a min: always smaller */ } while (1) { for (kcount = 0; kcount < 4; kcount++) { if (kcount >= 3 || n->elems[kcount] == NULL || (c = cmpret ? cmpret : cmp(e, n->elems[kcount])) < 0) { break; } if (n->kids[kcount]) idx += n->counts[kcount]; if (c == 0) { ecount = kcount; break; } idx++; } if (ecount >= 0) break; if (n->kids[kcount]) n = n->kids[kcount]; else break; } if (ecount >= 0) { /* * We have found the element we're looking for. It's * n->elems[ecount], at tree index idx. If our search * relation is EQ, LE or GE we can now go home. */ if (relation != REL234_LT && relation != REL234_GT) { if (index) *index = idx; return n->elems[ecount]; } /* * Otherwise, we'll do an indexed lookup for the previous * or next element. (It would be perfectly possible to * implement these search types in a non-counted tree by * going back up from where we are, but far more fiddly.) */ if (relation == REL234_LT) idx--; else idx++; } else { /* * We've found our way to the bottom of the tree and we * know where we would insert this node if we wanted to: * we'd put it in in place of the (empty) subtree * n->kids[kcount], and it would have index idx * * But the actual element isn't there. So if our search * relation is EQ, we're doomed. */ if (relation == REL234_EQ) return NULL; /* * Otherwise, we must do an index lookup for index idx-1 * (if we're going left - LE or LT) or index idx (if we're * going right - GE or GT). */ if (relation == REL234_LT || relation == REL234_LE) { idx--; } } /* * We know the index of the element we want; just call index234 * to do the rest. This will return NULL if the index is out of * bounds, which is exactly what we want. */ ret = index234(t, idx); if (ret && index) *index = idx; return ret;}void *find234(tree234 *t, void *e, cmpfn234 cmp) { return findrelpos234(t, e, cmp, REL234_EQ, NULL);}void *findrel234(tree234 *t, void *e, cmpfn234 cmp, int relation) { return findrelpos234(t, e, cmp, relation, NULL);}void *findpos234(tree234 *t, void *e, cmpfn234 cmp, int *index) { return findrelpos234(t, e, cmp, REL234_EQ, index);}/* * Delete an element e in a 2-3-4 tree. Does not free the element, * merely removes all links to it from the tree nodes. */static void *delpos234_internal(tree234 *t, int index) { node234 *n; void *retval; int ei = -1; retval = 0; n = t->root; LOG123(("deleting item %d from tree %p\n", index, t)); while (1) { while (n) { int ki; node234 *sub; LOG123((" node %p: %p/%d [%p] %p/%d [%p] %p/%d [%p] %p/%d index=%d\n", n, n->kids[0], n->counts[0], n->elems[0], n->kids[1], n->counts[1], n->elems[1], n->kids[2], n->counts[2], n->elems[2], n->kids[3], n->counts[3], index)); if (index < n->counts[0]) { ki = 0; } else if (index -= n->counts[0]+1, index < 0) { ei = 0; break; } else if (index < n->counts[1]) { ki = 1; } else if (index -= n->counts[1]+1, index < 0) { ei = 1; break; } else if (index < n->counts[2]) { ki = 2; } else if (index -= n->counts[2]+1, index < 0) { ei = 2; break; } else { ki = 3; } /* * Recurse down to subtree ki. If it has only one element, * we have to do some transformation to start with. */ LOG123((" moving to subtree %d\n", ki)); sub = n->kids[ki]; if (!sub->elems[1]) { LOG123((" subtree has only one element!\n", ki)); if (ki > 0 && n->kids[ki-1]->elems[1]) { /* * Case 3a, left-handed variant. Child ki has * only one element, but child ki-1 has two or * more. So we need to move a subtree from ki-1 * to ki. * * . C . . B . * / \ -> / \ * [more] a A b B c d D e [more] a A b c C d D e */ node234 *sib = n->kids[ki-1]; int lastelem = (sib->elems[2] ? 2 : sib->elems[1] ? 1 : 0); sub->kids[2] = sub->kids[1]; sub->counts[2] = sub->counts[1]; sub->elems[1] = sub->elems[0]; sub->kids[1] = sub->kids[0]; sub->counts[1] = sub->counts[0]; sub->elems[0] = n->elems[ki-1]; sub->kids[0] = sib->kids[lastelem+1]; sub->counts[0] = sib->counts[lastelem+1]; if (sub->kids[0]) sub->kids[0]->parent = sub; n->elems[ki-1] = sib->elems[lastelem]; sib->kids[lastelem+1] = NULL; sib->counts[lastelem+1] = 0; sib->elems[lastelem] = NULL; n->counts[ki] = countnode234(sub); LOG123((" case 3a left\n")); LOG123((" index and left subtree count before adjustment: %d, %d\n", index, n->counts[ki-1])); index += n->counts[ki-1]; n->counts[ki-1] = countnode234(sib); index -= n->counts[ki-1]; LOG123((" index and left subtree count after adjustment: %d, %d\n", index, n->counts[ki-1])); } else if (ki < 3 && n->kids[ki+1] && n->kids[ki+1]->elems[1]) { /* * Case 3a, right-handed variant. ki has only * one element but ki+1 has two or more. Move a * subtree from ki+1 to ki. * * . B . . C . * / \ -> / \ * a A b c C d D e [more] a A b B c d D e [more] */ node234 *sib = n->kids[ki+1]; int j; sub->elems[1] = n->elems[ki]; sub->kids[2] = sib->kids[0]; sub->counts[2] = sib->counts[0]; if (sub->kids[2]) sub->kids[2]->parent = sub; n->elems[ki] = sib->elems[0]; sib->kids[0] = sib->kids[1]; sib->counts[0] = sib->counts[1]; for (j = 0; j < 2 && sib->elems[j+1]; j++) { sib->kids[j+1] = sib->kids[j+2]; sib->counts[j+1] = sib->counts[j+2]; sib->elems[j] = sib->elems[j+1]; } sib->kids[j+1] = NULL; sib->counts[j+1] = 0; sib->elems[j] = NULL; n->counts[ki] = countnode234(sub); n->counts[ki+1] = countnode234(sib); LOG123((" case 3a right\n")); } else { /* * Case 3b. ki has only one element, and has no * neighbor with more than one. So pick a * neighbor and merge it with ki, taking an * element down from n to go in the middle. * * . B . . * / \ -> | * a A b c C d a A b B c C d * * (Since at all points we have avoided * descending to a node with only one element, * we can be sure that n is not reduced to * nothingness by this move, _unless_ it was * the very first node, ie the root of the * tree. In that case we remove the now-empty * root and replace it with its single large * child as shown.) */ node234 *sib; int j; if (ki > 0) { ki--; index += n->counts[ki] + 1; } sib = n->kids[ki]; sub = n->kids[ki+1]; sub->kids[3] = sub->kids[1]; sub->counts[3] = sub->counts[1]; sub->elems[2] = sub->elems[0]; sub->kids[2] = sub->kids[0]; sub->counts[2] = sub->counts[0]; sub->elems[1] = n->elems[ki]; sub->kids[1] = sib->kids[1]; sub->counts[1] = sib->counts[1]; if (sub->kids[1]) sub->kids[1]->parent = sub; sub->elems[0] = sib->elems[0]; sub->kids[0] = sib->kids[0]; sub->counts[0] = sib->counts[0]; if (sub->kids[0]) sub->kids[0]->parent = sub; n->counts[ki+1] = countnode234(sub); sfree(sib); /* * That's built the big node in sub. Now we * need to remove the reference to sib in n. */ for (j = ki; j < 3 && n->kids[j+1]; j++) { n->kids[j] = n->kids[j+1]; n->counts[j] = n->counts[j+1]; n->elems[j] = j<2 ? n->elems[j+1] : NULL; } n->kids[j] = NULL; n->counts[j] = 0; if (j < 3) n->elems[j] = NULL; LOG123((" case 3b ki=%d\n", ki)); if (!n->elems[0]) { /* * The root is empty and needs to be * removed. */ LOG123((" shifting root!\n")); t->root = sub; sub->parent = NULL; sfree(n); } } } n = sub; } if (!retval) retval = n->elems[ei]; if (ei==-1) return NULL; /* although this shouldn't happen */ /* * Treat special case: this is the one remaining item in * the tree. n is the tree root (no parent), has one * element (no elems[1]), and has no kids (no kids[0]). */ if (!n->parent && !n->elems[1] && !n->kids[0]) { LOG123((" removed last element in tree\n")); sfree(n); t->root = NULL; return retval; } /* * Now we have the element we want, as n->elems[ei], and we * have also arranged for that element not to be the only * one in its node. So... */ if (!n->kids[0] && n->elems[1]) { /* * Case 1. n is a leaf node with more than one element, * so it's _really easy_. Just delete the thing and * we're done. */ int i; LOG123((" case 1\n")); for (i = ei; i < 2 && n->elems[i+1]; i++) n->elems[i] = n->elems[i+1]; n->elems[i] = NULL; /* * Having done that to the leaf node, we now go back up * the tree fixing the counts. */ while (n->parent) { int childnum; childnum = (n->parent->kids[0] == n ? 0 : n->parent->kids[1] == n ? 1 : n->parent->kids[2] == n ? 2 : 3); n->parent->counts[childnum]--; n = n->parent; } return retval; /* finished! */ } else if (n->kids[ei]->elems[1]) { /* * Case 2a. n is an internal node, and the root of the * subtree to the left of e has more than one element. * So find the predecessor p to e (ie the largest node * in that subtree), place it where e currently is, and * then start the deletion process over again on the * subtree with p as target. */ node234 *m = n->kids[ei]; void *target; LOG123((" case 2a\n")); while (m->kids[0]) { m = (m->kids[3] ? m->kids[3] : m->kids[2] ? m->kids[2] : m->kids[1] ? m->kids[1] : m->kids[0]); } target = (m->elems[2] ? m->elems[2] : m->elems[1] ? m->elems[1] : m->elems[0]); n->elems[ei] = target; index = n->counts[ei]-1; n = n->kids[ei]; } else if (n->kids[ei+1]->elems[1]) { /* * Case 2b, symmetric to 2a but s/left/right/ and * s/predecessor/successor/. (And s/largest/smallest/). */ node234 *m = n->kids[ei+1]; void *target; LOG123((" case 2b\n")); while (m->kids[0]) { m = m->kids[0]; } target = m->elems[0]; n->elems[ei] = target; n = n->kids[ei+1]; index = 0; } else { /* * Case 2c. n is an internal node, and the subtrees to * the left and right of e both have only one element. * So combine the two subnodes into a single big node * with their own elements on the left and right and e * in the middle, then restart the deletion process on * that subtree, with e still as target. */ node234 *a = n->kids[ei], *b = n->kids[ei+1]; int j; LOG123((" case 2c\n")); a->elems[1] = n->elems[ei]; a->kids[2] = b->kids[0]; a->counts[2] = b->counts[0]; if (a->kids[2]) a->kids[2]->parent = a; a->elems[2] = b->elems[0]; a->kids[3] = b->kids[1]; a->counts[3] = b->counts[1]; if (a->kids[3]) a->kids[3]->parent = a; sfree(b); n->counts[ei] = countnode234(a); /* * That's built the big node in a, and destroyed b. Now * remove the reference to b (and e) in n. */ for (j = ei; j < 2 && n->elems[j+1]; j++) { n->elems[j] = n->elems[j+1]; n->kids[j+1] = n->kids[j+2]; n->counts[j+1] = n->counts[j+2]; } n->elems[j] = NULL; n->kids[j+1] = NULL; n->counts[j+1] = 0; /* * It's possible, in this case, that we've just removed * the only element in the root of the tree. If so, * shift the root. */ if (n->elems[0] == NULL) { LOG123((" shifting root!\n")); t->root = a; a->parent = NULL; sfree(n); } /* * Now go round the deletion process again, with n * pointing at the new big node and e still the same. */ n = a; index = a->counts[0] + a->counts[1] + 1; } }}void *delpos234(tree234 *t, int index) { if (index < 0 || index >= countnode234(t->root)) return NULL; return delpos234_internal(t, index);}void *del234(tree234 *t, void *e) { int index; if (!findrelpos234(t, e, NULL, REL234_EQ, &index)) return NULL; /* it wasn't in there anyway */ return delpos234_internal(t, index); /* it's there; delete it. */}#ifdef TEST/* * Test code for the 2-3-4 tree. This code maintains an alternative * representation of the data in the tree, in an array (using the * obvious and slow insert and delete functions). After each tree * operation, the verify() function is called, which ensures all * the tree properties are preserved: * - node->child->parent always equals node * - tree->root->parent always equals NULL
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -