📄 tree234.c
字号:
/* * Now (finally!) recurse into subtrees. */ count = nelems; for (i = 0; i < nkids; i++) { void *lower = (i == 0 ? lowbound : node->elems[i - 1]); void *higher = (i >= nelems ? highbound : node->elems[i]); int subcount = chknode(ctx, level + 1, node->kids[i], lower, higher); if (node->counts[i] != subcount) { error("node %p kid %d: count says %d, subtree really has %d", node, i, node->counts[i], subcount); } count += subcount; } return count;}void verifytree(tree234 * tree, void **array, int arraylen){ chkctx ctx; int i; void *p; ctx.treedepth = -1; /* depth unknown yet */ ctx.elemcount = 0; /* no elements seen yet */ /* * Verify validity of tree properties. */ if (tree->root) { if (tree->root->parent != NULL) error("root->parent is %p should be null", tree->root->parent); chknode(&ctx, 0, tree->root, NULL, NULL); } printf("tree depth: %d\n", ctx.treedepth); /* * Enumerate the tree and ensure it matches up to the array. */ for (i = 0; NULL != (p = index234(tree, i)); i++) { if (i >= arraylen) error("tree contains more than %d elements", arraylen); if (array[i] != p) error("enum at position %d: array says %s, tree says %s", i, array[i], p); } if (ctx.elemcount != i) { error("tree really contains %d elements, enum gave %d", ctx.elemcount, i); } if (i < arraylen) { error("enum gave only %d elements, array has %d", i, arraylen); } i = count234(tree); if (ctx.elemcount != i) { error("tree really contains %d elements, count234 gave %d", ctx.elemcount, i); }}void verify(void){ verifytree(tree, array, arraylen);}void internal_addtest(void *elem, int index, void *realret){ int i, j; void *retval; if (arraysize < arraylen + 1) { arraysize = arraylen + 1 + 256; array = (array == NULL ? smalloc(arraysize * sizeof(*array)) : srealloc(array, arraysize * sizeof(*array))); } i = index; /* now i points to the first element >= elem */ retval = elem; /* expect elem returned (success) */ for (j = arraylen; j > i; j--) array[j] = array[j - 1]; array[i] = elem; /* add elem to array */ arraylen++; if (realret != retval) { error("add: retval was %p expected %p", realret, retval); } verify();}void addtest(void *elem){ int i; void *realret; realret = add234(tree, elem); i = 0; while (i < arraylen && cmp(elem, array[i]) > 0) i++; if (i < arraylen && !cmp(elem, array[i])) { void *retval = array[i]; /* expect that returned not elem */ if (realret != retval) { error("add: retval was %p expected %p", realret, retval); } } else internal_addtest(elem, i, realret);}void addpostest(void *elem, int i){ void *realret; realret = addpos234(tree, elem, i); internal_addtest(elem, i, realret);}void delpostest(int i){ int index = i; void *elem = array[i], *ret; /* i points to the right element */ while (i < arraylen - 1) { array[i] = array[i + 1]; i++; } arraylen--; /* delete elem from array */ if (tree->cmp) ret = del234(tree, elem); else ret = delpos234(tree, index); if (ret != elem) { error("del returned %p, expected %p", ret, elem); } verify();}void deltest(void *elem){ int i; i = 0; while (i < arraylen && cmp(elem, array[i]) > 0) i++; if (i >= arraylen || cmp(elem, array[i]) != 0) return; /* don't do it! */ delpostest(i);}/* A sample data set and test utility. Designed for pseudo-randomness, * and yet repeatability. *//* * This random number generator uses the `portable implementation' * given in ANSI C99 draft N869. It assumes `unsigned' is 32 bits; * change it if not. */int randomnumber(unsigned *seed){ *seed *= 1103515245; *seed += 12345; return ((*seed) / 65536) % 32768;}int mycmp(void *av, void *bv){ char const *a = (char const *) av; char const *b = (char const *) bv; return strcmp(a, b);}#define lenof(x) ( sizeof((x)) / sizeof(*(x)) )char *strings[] = { "0", "2", "3", "I", "K", "d", "H", "J", "Q", "N", "n", "q", "j", "i", "7", "G", "F", "D", "b", "x", "g", "B", "e", "v", "V", "T", "f", "E", "S", "8", "A", "k", "X", "p", "C", "R", "a", "o", "r", "O", "Z", "u", "6", "1", "w", "L", "P", "M", "c", "U", "h", "9", "t", "5", "W", "Y", "m", "s", "l", "4",#if 0 "a", "ab", "absque", "coram", "de", "palam", "clam", "cum", "ex", "e", "sine", "tenus", "pro", "prae", "banana", "carrot", "cabbage", "broccoli", "onion", "zebra", "penguin", "blancmange", "pangolin", "whale", "hedgehog", "giraffe", "peanut", "bungee", "foo", "bar", "baz", "quux", "murfl", "spoo", "breen", "flarn", "octothorpe", "snail", "tiger", "elephant", "octopus", "warthog", "armadillo", "aardvark", "wyvern", "dragon", "elf", "dwarf", "orc", "goblin", "pixie", "basilisk", "warg", "ape", "lizard", "newt", "shopkeeper", "wand", "ring", "amulet"#endif};#define NSTR lenof(strings)void findtest(void){ static const int rels[] = { REL234_EQ, REL234_GE, REL234_LE, REL234_LT, REL234_GT }; static const char *const relnames[] = { "EQ", "GE", "LE", "LT", "GT" }; int i, j, rel, index; char *p, *ret, *realret, *realret2; int lo, hi, mid, c; for (i = 0; i < (int) NSTR; i++) { p = strings[i]; for (j = 0; j < (int) (sizeof(rels) / sizeof(*rels)); j++) { rel = rels[j]; lo = 0; hi = arraylen - 1; while (lo <= hi) { mid = (lo + hi) / 2; c = strcmp(p, array[mid]); if (c < 0) hi = mid - 1; else if (c > 0) lo = mid + 1; else break; } if (c == 0) { if (rel == REL234_LT) ret = (mid > 0 ? array[--mid] : NULL); else if (rel == REL234_GT) ret = (mid < arraylen - 1 ? array[++mid] : NULL); else ret = array[mid]; } else { assert(lo == hi + 1); if (rel == REL234_LT || rel == REL234_LE) { mid = hi; ret = (hi >= 0 ? array[hi] : NULL); } else if (rel == REL234_GT || rel == REL234_GE) { mid = lo; ret = (lo < arraylen ? array[lo] : NULL); } else ret = NULL; } realret = findrelpos234(tree, p, NULL, rel, &index); if (realret != ret) { error("find(\"%s\",%s) gave %s should be %s", p, relnames[j], realret, ret); } if (realret && index != mid) { error("find(\"%s\",%s) gave %d should be %d", p, relnames[j], index, mid); } if (realret && rel == REL234_EQ) { realret2 = index234(tree, index); if (realret2 != realret) { error("find(\"%s\",%s) gave %s(%d) but %d -> %s", p, relnames[j], realret, index, index, realret2); } }#if 0 printf("find(\"%s\",%s) gave %s(%d)\n", p, relnames[j], realret, index);#endif } } realret = findrelpos234(tree, NULL, NULL, REL234_GT, &index); if (arraylen && (realret != array[0] || index != 0)) { error("find(NULL,GT) gave %s(%d) should be %s(0)", realret, index, array[0]); } else if (!arraylen && (realret != NULL)) { error("find(NULL,GT) gave %s(%d) should be NULL", realret, index); } realret = findrelpos234(tree, NULL, NULL, REL234_LT, &index); if (arraylen && (realret != array[arraylen - 1] || index != arraylen - 1)) { error("find(NULL,LT) gave %s(%d) should be %s(0)", realret, index, array[arraylen - 1]); } else if (!arraylen && (realret != NULL)) { error("find(NULL,LT) gave %s(%d) should be NULL", realret, index); }}void splittest(tree234 * tree, void **array, int arraylen){ int i; tree234 *tree3, *tree4; for (i = 0; i <= arraylen; i++) { tree3 = copytree234(tree, NULL, NULL); tree4 = splitpos234(tree3, i, 0); verifytree(tree3, array, i); verifytree(tree4, array + i, arraylen - i); join234(tree3, tree4); freetree234(tree4); /* left empty by join */ verifytree(tree3, array, arraylen); freetree234(tree3); }}int main(void){ int in[NSTR]; int i, j, k; int tworoot, tmplen; unsigned seed = 0; tree234 *tree2, *tree3, *tree4; int c; setvbuf(stdout, NULL, _IOLBF, 0); for (i = 0; i < (int) NSTR; i++) in[i] = 0; array = NULL; arraylen = arraysize = 0; tree = newtree234(mycmp); cmp = mycmp; verify(); for (i = 0; i < 10000; i++) { j = randomnumber(&seed); j %= NSTR; printf("trial: %d\n", i); if (in[j]) { printf("deleting %s (%d)\n", strings[j], j); deltest(strings[j]); in[j] = 0; } else { printf("adding %s (%d)\n", strings[j], j); addtest(strings[j]); in[j] = 1; } disptree(tree); findtest(); } while (arraylen > 0) { j = randomnumber(&seed); j %= arraylen; deltest(array[j]); } freetree234(tree); /* * Now try an unsorted tree. We don't really need to test * delpos234 because we know del234 is based on it, so it's * already been tested in the above sorted-tree code; but for * completeness we'll use it to tear down our unsorted tree * once we've built it. */ tree = newtree234(NULL); cmp = NULL; verify(); for (i = 0; i < 1000; i++) { printf("trial: %d\n", i); j = randomnumber(&seed); j %= NSTR; k = randomnumber(&seed); k %= count234(tree) + 1; printf("adding string %s at index %d\n", strings[j], k); addpostest(strings[j], k); } /* * While we have this tree in its full form, we'll take a copy * of it to use in split and join testing. */ tree2 = copytree234(tree, NULL, NULL); verifytree(tree2, array, arraylen); /* check the copy is accurate */ /* * Split tests. Split the tree at every possible point and * check the resulting subtrees. */ tworoot = (!tree2->root->elems[1]); /* see if it has a 2-root */ splittest(tree2, array, arraylen); /* * Now do the split test again, but on a tree that has a 2-root * (if the previous one didn't) or doesn't (if the previous one * did). */ tmplen = arraylen; while ((!tree2->root->elems[1]) == tworoot) { delpos234(tree2, --tmplen); } printf("now trying splits on second tree\n"); splittest(tree2, array, tmplen); freetree234(tree2); /* * Back to the main testing of uncounted trees. */ while (count234(tree) > 0) { printf("cleanup: tree size %d\n", count234(tree)); j = randomnumber(&seed); j %= count234(tree); printf("deleting string %s from index %d\n", (char *) array[j], j); delpostest(j); } freetree234(tree); /* * Finally, do some testing on split/join on _sorted_ trees. At * the same time, we'll be testing split on very small trees. */ tree = newtree234(mycmp); cmp = mycmp; arraylen = 0; for (i = 0; i < 16; i++) { addtest(strings[i]); tree2 = copytree234(tree, NULL, NULL); splittest(tree2, array, arraylen); freetree234(tree2); } freetree234(tree); /* * Test silly cases of join: join(emptytree, emptytree), and * also ensure join correctly spots when sorted trees fail the * ordering constraint. */ tree = newtree234(mycmp); tree2 = newtree234(mycmp); tree3 = newtree234(mycmp); tree4 = newtree234(mycmp); assert(mycmp(strings[0], strings[1]) < 0); /* just in case :-) */ add234(tree2, strings[1]); add234(tree4, strings[0]); array[0] = strings[0]; array[1] = strings[1]; verifytree(tree, array, 0); verifytree(tree2, array + 1, 1); verifytree(tree3, array, 0); verifytree(tree4, array, 1); /* * So: * - join(tree,tree3) should leave
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -