/* * Search for the node which contains "value". The algorithm is a * simple binary tree search. * * return value: * NULL: the value is not in the AVL tree * *where (if not NULL) is set to indicate the insertion point * "void *" of the found tree node */ void * avl_find(avl_tree_t *tree, void *value, avl_index_t *where) { avl_node_t *node; avl_node_t *prev = NULL; int child = 0; int diff; size_t off = tree->avl_offset; for (node = tree->avl_root; node != NULL; node = node->avl_child[child]) { prev = node; diff = tree->avl_compar(value, AVL_NODE2DATA(node, off)); if (!((-1 <= diff) && (diff <= 1))) { filebench_log(LOG_ERROR, "avl compare error"); return (NULL); } if (diff == 0) { if (where != NULL) *where = 0; return (AVL_NODE2DATA(node, off)); } child = avl_balance2child[1 + diff]; } if (where != NULL) *where = AVL_MKINDEX(prev, child); return (NULL); }
/* * Search for the node which contains "value". The algorithm is a * simple binary tree search. * * return value: * NULL: the value is not in the AVL tree * *where (if not NULL) is set to indicate the insertion point * "void *" of the found tree node */ void * avl_find(avl_tree_t *tree, const void *value, avl_index_t *where) { avl_node_t *node; avl_node_t *prev = NULL; int child = 0; int diff; size_t off = tree->avl_offset; for (node = tree->avl_root; node != NULL; node = node->avl_child[child]) { prev = node; diff = tree->avl_compar(value, AVL_NODE2DATA(node, off)); //ASSERT(-1 <= diff && diff <= 1); if (diff == 0) { #ifdef DEBUG if (where != NULL) *where = 0; #endif return (AVL_NODE2DATA(node, off)); } child = avl_balance2child[1 + diff]; } if (where != NULL) *where = AVL_MKINDEX(prev, child); return (NULL); }
/* * Insert "new_data" in "tree" in the given "direction" either after or * before (AVL_AFTER, AVL_BEFORE) the data "here". * * Insertions can only be done at empty leaf points in the tree, therefore * if the given child of the node is already present we move to either * the AVL_PREV or AVL_NEXT and reverse the insertion direction. Since * every other node in the tree is a leaf, this always works. * * To help developers using this interface, we assert that the new node * is correctly ordered at every step of the way in DEBUG kernels. */ void avl_insert_here( avl_tree_t *tree, void *new_data, void *here, int direction) { avl_node_t *node; int child = direction; /* rely on AVL_BEFORE == 0, AVL_AFTER == 1 */ #ifdef DEBUG int diff; #endif //ASSERT(tree != NULL); //ASSERT(new_data != NULL); //ASSERT(here != NULL); //ASSERT(direction == AVL_BEFORE || direction == AVL_AFTER); /* * If corresponding child of node is not NULL, go to the neighboring * node and reverse the insertion direction. */ node = AVL_DATA2NODE(here, tree->avl_offset); #ifdef DEBUG diff = tree->avl_compar(new_data, here); //ASSERT(-1 <= diff && diff <= 1); //ASSERT(diff != 0); //ASSERT(diff > 0 ? child == 1 : child == 0); #endif if (node->avl_child[child] != NULL) { node = node->avl_child[child]; child = 1 - child; while (node->avl_child[child] != NULL) { #ifdef DEBUG diff = tree->avl_compar(new_data, AVL_NODE2DATA(node, tree->avl_offset)); //ASSERT(-1 <= diff && diff <= 1); //ASSERT(diff != 0); //ASSERT(diff > 0 ? child == 1 : child == 0); #endif node = node->avl_child[child]; } #ifdef DEBUG diff = tree->avl_compar(new_data, AVL_NODE2DATA(node, tree->avl_offset)); //ASSERT(-1 <= diff && diff <= 1); //ASSERT(diff != 0); //ASSERT(diff > 0 ? child == 1 : child == 0); #endif } //ASSERT(node->avl_child[child] == NULL); avl_insert(tree, new_data, AVL_MKINDEX(node, child)); }
/* * Return the highest valued node in a tree or NULL. * (rightmost child from root of tree) */ void * avl_last(avl_tree_t *tree) { avl_node_t *node; avl_node_t *prev = NULL; size_t off = tree->avl_offset; for (node = tree->avl_root; node != NULL; node = node->avl_child[1]) prev = node; if (prev != NULL) return (AVL_NODE2DATA(prev, off)); return (NULL); }
/* * Return the lowest valued node in a tree or NULL. * (leftmost child from root of tree) */ void * avl_first(avl_tree_t *tree) { avl_node_t *node; avl_node_t *prev = NULL; unsigned int off = tree->avl_offset; for (node = tree->avl_root; node != NULL; node = node->avl_child[0]) prev = node; if (prev != NULL) return (AVL_NODE2DATA(prev, off)); return (NULL); }
/* * Access the node immediately before or after an insertion point. * * "avl_index_t" is a (avl_node_t *) with the bottom bit indicating a child * * Return value: * NULL: no node in the given direction * "void *" of the found tree node */ void * avl_nearest(avl_tree_t *tree, avl_index_t where, int direction) { int child = AVL_INDEX2CHILD(where); avl_node_t *node = AVL_INDEX2NODE(where); void *data; size_t off = tree->avl_offset; if (node == NULL) { return (NULL); } data = AVL_NODE2DATA(node, off); if (child != direction) return (data); return (avl_walk(tree, data, direction)); }
/* * Walk from one node to the previous valued node (ie. an infix walk * towards the left). At any given node we do one of 2 things: * * - If there is a left child, go to it, then to it's rightmost descendant. * * - otherwise we return thru parent nodes until we've come from a right child. * * Return Value: * NULL - if at the end of the nodes * otherwise next node */ void * avl_walk(avl_tree_t *tree, void *oldnode, int left) { size_t off = tree->avl_offset; avl_node_t *node = AVL_DATA2NODE(oldnode, off); int right = 1 - left; int was_child; /* * nowhere to walk to if tree is empty */ if (node == NULL) return (NULL); /* * Visit the previous valued node. There are two possibilities: * * If this node has a left child, go down one left, then all * the way right. */ if (node->avl_child[left] != NULL) { for (node = node->avl_child[left]; node->avl_child[right] != NULL; node = node->avl_child[right]) ; /* * Otherwise, return thru left children as far as we can. */ } else { for (;;) { was_child = AVL_XCHILD(node); node = AVL_XPARENT(node); if (node == NULL) return (NULL); if (was_child == right) break; } } return (AVL_NODE2DATA(node, off)); }
/* * Access the node immediately before or after an insertion point. * * "avl_index_t" is a (avl_node_t *) with the bottom bit indicating a child * * Return value: * NULL: no node in the given direction * "void *" of the found tree node */ void * avl_nearest(avl_tree_t *tree, avl_index_t where, int direction) { int child = AVL_INDEX2CHILD(where); avl_node_t *node = AVL_INDEX2NODE(where); void *data; size_t off = tree->avl_offset; if (node == NULL) { if (tree->avl_root != NULL) filebench_log(LOG_ERROR, "Null Node Pointer Supplied"); return (NULL); } data = AVL_NODE2DATA(node, off); if (child != direction) return (data); return (avl_walk(tree, data, direction)); }