#include #include #include #include #include "AVLtree.h" #define TEST_MAIN #define PRINT_AFTER_OPERATIONS int treeHeight(const struct tree *root) { if(root == 0) { return TREE_EMPTY_HEIGHT; } else { return root->height; } } /* recompute height from height of kids */ static int treeComputeHeight(const struct tree *root) { int childHeight; int maxChildHeight; int i; if(root == 0) { return TREE_EMPTY_HEIGHT; } else { maxChildHeight = TREE_EMPTY_HEIGHT; for(i = 0; i < TREE_NUM_CHILDREN; i++) { childHeight = treeHeight(root->child[i]); if(childHeight > maxChildHeight) { maxChildHeight = childHeight; } } return maxChildHeight + 1; } } size_t treeSize(const struct tree *root) { if(root == 0) { return 0; } else { return root->size; } } /* recompute size from size of kids */ static int treeComputeSize(const struct tree *root) { int size; int i; if(root == 0) { return 0; } else { size = 1; for(i = 0; i < TREE_NUM_CHILDREN; i++) { size += treeSize(root->child[i]); } return size; } } /* fix aggregate data in root */ /* assumes children are correct */ static void treeFix(struct tree *root) { if(root) { root->height = treeComputeHeight(root); root->size = treeComputeSize(root); } } /* rotate child in given direction to root */ static void treeRotate(struct tree **root, int direction) { struct tree *x; struct tree *y; struct tree *b; /* * y x * / \ / \ * x C <=> A y * / \ / \ * A B B C */ y = *root; assert(y); x = y->child[direction]; assert(x); b = x->child[!direction]; /* do the rotation */ *root = x; x->child[!direction] = y; y->child[direction] = b; /* fix y then x */ treeFix(y); treeFix(x); } /* restore AVL property at *root after an insertion or deletion */ static void treeRebalance(struct tree **root) { int tallerKid; if(*root) { for(tallerKid = 0; tallerKid < TREE_NUM_CHILDREN; tallerKid++) { if(treeHeight((*root)->child[tallerKid]) >= treeHeight((*root)->child[!tallerKid]) + 2) { /* check if zig-zag: opposite-direction nephew is the tall one */ /* this also covers case where both nephews are too tall */ if(treeHeight((*root)->child[tallerKid]->child[!tallerKid]) >= treeHeight((*root)->child[tallerKid]) - 1) { /* zig zag case */ treeRotate(&(*root)->child[tallerKid], !tallerKid); } /* fall through to zig zig case */ treeRotate(root, tallerKid); /* don't bother with other kid */ break; } } } } /* free all elements of a tree, replacing it with TREE_EMPTY */ void treeDestroy(struct tree **root) { int i; if(*root) { for(i = 0; i < TREE_NUM_CHILDREN; i++) { treeDestroy(&(*root)->child[i]); } free(*root); *root = 0; } } /* insert an element into a tree pointed to by root */ void treeInsert(struct tree **root, int newElement) { struct tree *e; printf("INSERT element: %d\n", newElement); if(*root == 0) { /* not already there, put it in */ e = malloc(sizeof(*e)); assert(e); e->key = newElement; e->child[LEFT] = e->child[RIGHT] = 0; *root = e; } else { /* do this recursively so we can fix data on the way back out */ treeInsert(&(*root)->child[(*root)->key < newElement], newElement); } /* fix the aggregate data */ treeFix(*root); treeRebalance(root); } /* return 1 if target is in tree, 0 otherwise */ int treeContains(const struct tree *t, int target) { while(t && t->key != target) { t = t->child[t->key < target]; } return t != 0; } /* delete minimum element from the tree and return its key */ /* do not call this on an empty tree */ int treeDeleteMin(struct tree **root) { struct tree *toFree; int retval; assert(*root); /* can't delete min from empty tree */ if((*root)->child[LEFT]) { /* recurse on left subtree */ printf("DELETE: left child\n"); retval = treeDeleteMin(&(*root)->child[LEFT]); } else { /* delete the root */ printf("DELETE: root\n"); toFree = *root; retval = toFree->key; *root = toFree->child[RIGHT]; free(toFree); } /* fix the aggregate data */ treeFix(*root); treeRebalance(root); return retval; } /* delete target from the tree */ /* has no effect if target is not in tree */ void treeDelete(struct tree **root, int target) { struct tree *toFree; /* do nothing if target not in tree */ if(*root) { if((*root)->key == target) { if((*root)->child[RIGHT]) { /* replace root with min value in right subtree */ (*root)->key = treeDeleteMin(&(*root)->child[RIGHT]); } else { /* patch out root */ toFree = *root; *root = toFree->child[LEFT]; free(toFree); } } else { treeDelete(&(*root)->child[(*root)->key < target], target); } /* fix the aggregate data */ treeFix(*root); treeRebalance(root); } } /* how far to indent each level of the tree */ #define INDENTATION_LEVEL (2) /* print contents of a tree, indented by depth */ static void treePrintIndented(const struct tree *root, int depth) { int i; if(root != 0) { treePrintIndented(root->child[LEFT], depth+1); for(i = 0; i < INDENTATION_LEVEL*depth; i++) { putchar(' '); } printf("%d Height: %d Size: %lu (%p)\n", root->key, root->height, root->size, (void *) root); treePrintIndented(root->child[RIGHT], depth+1); } } /* print the contents of a tree */ void treePrint(const struct tree *root) { treePrintIndented(root, 0); } size_t treeRank(const struct tree *t, int target) { size_t rank = 0; while(t && t->key != target) { if(t->key < target) { /* go right */ /* root and left subtree are all less than target */ rank += (1 + treeSize(t->child[LEFT])); t = t->child[RIGHT]; } else { /* go left */ t = t->child[LEFT]; } } /* we must also count left subtree */ return rank + treeSize(t->child[LEFT]); } int treeUnrank(const struct tree *t, size_t rank) { size_t leftSize; /* basic idea: if rank < treeSize(child[LEFT]), recurse in left child */ /* if it's equal, return the root */ /* else recurse in right child with rank = rank - treeSize(child[LEFT]) - 1 */ while(rank != (leftSize = treeSize(t->child[LEFT]))) { if(rank < leftSize) { t = t->child[LEFT]; } else { t = t->child[RIGHT]; rank -= (leftSize + 1); } } return t->key; } #ifdef TEST_MAIN /* check that aggregate data is correct throughout the tree */ static void treeSanityCheck(const struct tree *root) { int i; if(root) { assert(root->height == treeComputeHeight(root)); assert(root->size == treeComputeSize(root)); for(i = 0; i < TREE_NUM_CHILDREN; i++) { treeSanityCheck(root->child[i]); } } } int main(int argc, char **argv) { int i; const int n = 10; struct tree *root = TREE_EMPTY; if(argc != 1) { fprintf(stderr, "Usage: %s\n", argv[0]); return 1; } for(i = 0; i < n; i++) { assert(!treeContains(root, i)); treeInsert(&root, i); assert(treeContains(root, i)); #ifdef PRINT_AFTER_OPERATIONS treePrint(root); puts("---"); #endif } /* check ranks */ for(i = 0; i < n; i++) { assert(treeRank(root, i) == i); assert(treeUnrank(root, i) == i); } treeSanityCheck(root); /* now delete everything */ for(i = 0; i < n; i++) { assert(treeContains(root, i)); treeDelete(&root, i); assert(!treeContains(root, i)); #ifdef PRINT_AFTER_OPERATIONS treePrint(root); puts("---"); #endif } treeSanityCheck(root); treeDestroy(&root); return 0; } #endif