diff --git a/src/Makefile.am b/src/Makefile.am index 06c9ab8..6877414 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,13 +8,13 @@ CALG_HEADERFILES=\ arraylist.h compare-int.h hash-int.h hash-table.h set.h \ avl-tree.h compare-pointer.h hash-pointer.h list.h slist.h \ queue.h compare-string.h hash-string.h trie.h binary-heap.h \ -bloom-filter.h binomial-heap.h rb-tree.h sortedarray.h +bloom-filter.h binomial-heap.h rb-tree.h sortedarray.h tree.h SRC=\ arraylist.c compare-pointer.c hash-pointer.c list.c slist.c \ avl-tree.c compare-string.c hash-string.c queue.c trie.c \ compare-int.c hash-int.c hash-table.c set.c binary-heap.c \ -bloom-filter.c binomial-heap.c rb-tree.c sortedarray.c +bloom-filter.c binomial-heap.c rb-tree.c sortedarray.c tree.c libcalgtest_a_CFLAGS=$(TEST_CFLAGS) -DALLOC_TESTING -I../test -g libcalgtest_a_SOURCES=$(SRC) $(MAIN_HEADERFILES) diff --git a/src/tree.c b/src/tree.c new file mode 100644 index 0000000..7c37287 --- /dev/null +++ b/src/tree.c @@ -0,0 +1,778 @@ +/* + +Copyright (c) 2016, Stefan Cloudt + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +#include "tree.h" +#include +#include +#include + +/** + * The structure of a tree node. + */ +struct _TreeNode { + /** + * The parent of a node. + */ + TreeNode* parent; + + /** + * The children of the node. This is an array whose size is _alloced. All + * elements in the range [0,outDegree) are defined and not null. + */ + TreeNode** children; + + /** + * The amount of children of this node. + */ + unsigned int outDegree; + + /** + * The data this node stores. + */ + TreeNodeValue data; + + /** + * The allocated size of children. + */ + unsigned int _alloced; + + /** + * The current position of this node in its parent's child array. + */ + unsigned int i; + + /** + * The height of this node. + */ + unsigned int h; +}; + +struct _TreeIterator { + Tree* t; + TreeNode* prev; + TreeNode* current; + TreeNode* next; +}; + +/* Updates the height values for the nodes when n is changed. */ +static void tree_update_height(TreeNode* n) +{ + while (n != NULL) { + unsigned int h = 0; + unsigned int i = 0; + for (i = 0; i < n->outDegree; i++) { + h = (h > n->children[i]->h) ? h : n->children[i]->h; + } + + n->h = h; + n = n->parent; + } +} + +/* Grows the internal children array to size s if it is smaller. */ +static int tree_children_grow_min_size(TreeNode* n, unsigned int s) +{ + TreeNode** arr; + + if (n->_alloced >= s) { + return 1; + } + + arr = realloc(n->children, sizeof(TreeNode*) * s); + + if (arr == NULL) { + return 0; + } + + n->children = arr; + n->_alloced = s; + + return 1; +} + +/* Removes node c as child from its parent child array. */ +static void tree_node_remove_child(TreeNode* c) + +{ + TreeNode* p = c->parent; + unsigned int i = 0; + + /* Loop to the place where c resides. */ + for (i = 0; i < p->outDegree && p->children[i] != c; i++); + + p->children[i] = NULL; + + /* Move all others one place back. */ + for (; i < p->outDegree - 1; i++) { + p->children[i] = p->children[i+1]; + p->children[i]->i = i; + } + + p->outDegree--; +} + +Tree* tree_alloc(TreeNodeValue data) +{ + Tree* t = malloc(sizeof(struct _TreeNode)); + + if (t == NULL) { + return NULL; + } + + t->parent = NULL; + t->children = NULL; + t->outDegree = 0; + t->data = data; + t->_alloced = 0; + t->i = 0; + t->h = 0; + + return t; +} + +void tree_free(Tree* t) +{ + if (t != NULL) { + unsigned int i; + + for (i = 0; i < t->outDegree; i++) { + tree_free(t->children[i]); + } + + free(t->children); + free(t); + } +} + +TreeNode* tree_root(Tree* t) +{ + return t; +} + +TreeNode* tree_abs_root(TreeNode* n) +{ + TreeNode* b = n; + + while (n != NULL) { + b = n; + n = n->parent; + } + + return b; +} + +Tree* tree_subtree(TreeNode* n) +{ + return n; +} + +TreeNodeValue tree_data(TreeNode* n) +{ + return n->data; +} + +void tree_set_data(TreeNode* n, TreeNodeValue d) +{ + n->data = d; +} + +TreeNode* tree_parent(Tree* t, TreeNode* n) +{ + if (n == NULL) { + return NULL; + } + + /* If t == n then n is root of t so no parent in t. */ + if (t == n) { + return NULL; + } + + return n->parent; +} + +TreeNode* tree_child(TreeNode* n, unsigned int i) +{ + if (tree_out_degree(n) > i) { + return n->children[i]; + } + else { + return NULL; + } +} + +TreeNode* tree_first_child(TreeNode* n) +{ + if (tree_out_degree(n) > 0) { + return n->children[0]; + } + else { + return NULL; + } +} + +TreeNode* tree_last_child(TreeNode* n) +{ + unsigned int od = tree_out_degree(n); + + if (od > 0) { + /* By def of tree node this cannot be NULL. */ + return n->children[od - 1]; + } + else { + return NULL; + } +} + +unsigned int tree_out_degree(TreeNode* n) +{ + return n->outDegree; +} + +TreeNode** tree_children(TreeNode* n) +{ + if (tree_out_degree(n) == 0) { + return NULL; + } + else { + return n->children; + } +} + +int tree_is_leaf(TreeNode* n) +{ + return tree_out_degree(n) == 0; +} + +int tree_is_descendant_of(TreeNode* d, TreeNode* n) +{ + while (d != NULL && d != n) { + d = d->parent; + } + + return d == n; +} + +int tree_is_ancestor_of(TreeNode* a, TreeNode* n) +{ + return tree_is_descendant_of(n, a); +} + +unsigned int tree_depth(Tree* t, TreeNode* n) +{ + unsigned int d = 0; + + if (!tree_is_ancestor_of(t, n)) { + return 0; + } + + while (n != NULL && n != t) { + n = n->parent; + d++; + } + + return d; +} + +unsigned int tree_level( + Tree* t, + TreeNode* n) +{ + if (!tree_is_ancestor_of(t, n)) { + return 0; + } + + return tree_depth(t, n) + 1; +} + +unsigned int tree_height(Tree* t) +{ + if (t == NULL) { + return 0; + } + + return t->h; +} + +unsigned int tree_height_node(TreeNode* n) +{ + return n->h; +} + +Tree* tree_remove(TreeNode* n) +{ + if (n->parent == NULL) { + return n; + } + + /* Remove n from children of p. */ + tree_node_remove_child(n); + + tree_update_height(n->parent); + + n->parent = NULL; + n->i = 0; + + return n; +} + +void tree_delete(TreeNode* n) +{ + TreeNode* r = tree_remove(n); + tree_free(r); +} + +Tree* tree_add_subtree(TreeNode* n, Tree* t) +{ + if (t == NULL || t->parent != NULL) { + return NULL; + } + + (void) tree_remove((TreeNode*) t); + + if (!tree_children_grow_min_size(n, n->outDegree + 1)) { + return t; + } + + n->children[n->outDegree] = t; + + t->parent = n; + t->i = n->outDegree; + n->outDegree++; + + tree_update_height(n); + + return NULL; +} + +TreeNode* tree_add_child(TreeNode* n, TreeNodeValue data) +{ + TreeNode* c; + + if (!tree_children_grow_min_size(n, n->outDegree + 1)) { + return NULL; + } + + c = tree_alloc(data); + + if (c == NULL) { + return NULL; + } + + n->children[n->outDegree] = c; + + c->parent = n; + c->i = n->outDegree; + n->outDegree++; + + tree_update_height(n); + + return c; +} + +Tree* tree_insert_subtree(TreeNode* n, Tree* t, unsigned int i) +{ + unsigned int a; + + if (t == NULL || i > n->outDegree || t->parent != NULL) { + return t; + } + + if (!tree_children_grow_min_size(n, n->outDegree + 1)) { + return t; + } + + /* create space for t */ + for (a = n->outDegree - 1; a >= i; a--) { + n->children[a + 1] = n->children[a]; + n->children[a + 1]->i = a + 1; + } + + n->children[i] = t; + n->outDegree++; + + t->parent = n; + t->i = i; + + tree_update_height(n); + + return NULL; +} + +TreeNode* tree_insert_child(TreeNode* n, TreeNodeValue data, unsigned int i) +{ + TreeNode* c; + + if (i > n->outDegree) { + return NULL; + } + + c = tree_alloc(data); + c = tree_insert_subtree(n, c, i); + + if (c == NULL) { + return c; + } + else { + tree_free(c); + return NULL; + } +} + +Tree* tree_set_subtree(TreeNode* n, Tree* t, unsigned int i) +{ + if (t == NULL || i > n->outDegree || t->parent != NULL) { + return t; + } + + if (!tree_children_grow_min_size(n, n->outDegree + 1)) { + return t; + } + + if (i == n->outDegree) { + n->children[i] = t; + n->outDegree++; + } + else { + tree_free(n->children[i]); + n->children[i] = t; + } + + t->parent = n; + t->i = i; + + tree_update_height(n); + + return NULL; +} + +TreeNode* tree_set_child(TreeNode* n, TreeNodeValue data, unsigned int i) +{ + TreeNode* c; + + if (i > n->outDegree) { + return NULL; + } + + c = tree_alloc(data); + c = tree_set_subtree(n, c, i); + + if (c == NULL) { + return c; + } + else { + tree_free(c); + return NULL; + } +} + +TreeNodeValue tree_iter_data(TreeIterator* i) +{ + if (i->current == NULL) { + return NULL; + } + + return i->current->data; +} + +int tree_iter_has_next(TreeIterator* i) +{ + return i->next != NULL; +} + +int tree_iter_has_prev(TreeIterator* i) +{ + return i->prev != NULL; +} + +TreeIterator* tree_iter_alloc() +{ + TreeIterator* i = malloc(sizeof(TreeIterator)); + + if (i == NULL) { + return NULL; + } + + i->current = NULL; + i->t = NULL; + i->next = NULL; + i->prev = NULL; + + return i; +} + +void tree_iter_free(TreeIterator* i) +{ + free(i); +} + +void tree_iter_leaves_first(TreeIterator* i, Tree* t) +{ + TreeNode* nc = t; + TreeNode* cc = t; + + i->t = t; + + while (nc != NULL) { + cc = nc; + + if (cc->outDegree > 0) { + nc = nc->children[0]; + } + else { + nc = NULL; + } + } + + i->next = cc; +} + +void tree_iter_leaves_last(TreeIterator* i, Tree* t) +{ + TreeNode* nc = t; + TreeNode* cc = t; + + i->t = t; + + while (nc != NULL) { + cc = nc; + + if (cc->outDegree > 0) { + nc = nc->children[nc->outDegree - 1]; + } + else { + nc = NULL; + } + } + + i->prev = cc; +} + +TreeNode* tree_iter_leaves_next(TreeIterator* i) +{ + TreeNode* p; + + i->prev = i->current; + i->current = i->next; + + /* Find layer where there is a right sibling. */ + p = i->next; + while (p != NULL && p != i->t) { + if (p->parent != NULL && p->i < p->parent->outDegree - 1) { + break; + } + + p = p->parent; + } + + if (p == NULL || p == i->t) { + i->next = NULL; + return i->current; + } + + /* Now move down the right branch to it's children. */ + p = p->parent->children[p->i + 1]; + while (p->outDegree > 0) { + p = p->children[0]; + } + + i->next = p; + + return i->current; +} + +TreeNode* tree_iter_leaves_prev(TreeIterator* i) +{ + TreeNode* p; + + i->next = i->current; + i->current = i->prev; + + /* Find layer where there is a left sibling. */ + p = i->prev; + while (p != NULL && p != i->t) { + if (p->i > 0) { + break; + } + + p = p->parent; + } + + if (p == NULL || p == i->t) { + i->prev = NULL; + return i->current; + } + + /* Now we go down to find the previous child */ + p = p->parent->children[p->i - 1]; + while (p->outDegree > 0) { + p = p->children[p->outDegree - 1]; + } + + i->prev = p; + + return i->current; +} + +void tree_iter_parents(TreeIterator* i, Tree* t, TreeNode* n) +{ + i->t = t; + i->prev = NULL; + i->current = NULL; + i->next = n; +} + +TreeNode* tree_iter_parents_next(TreeIterator* i) +{ + i->prev = i->current; + i->current = i->next; + + if (i->next != NULL && i->next != i->t) { + i->next = i->next->parent; + } + else { + i->next = NULL; + } + + return i->current; +} + +void tree_preorder_walk(TreeIterator* i, Tree* t) +{ + i->t = t; + i->next = t; + i->current = NULL; + i->prev = NULL; +} + +TreeNode* tree_preorder_walk_next(TreeIterator* i) +{ + i->prev = i->current; + i->current = i->next; + + if (i->next == NULL) { + return i->current; + } + + if (i->next->outDegree > 0) { + i->next = i->next->children[0]; + return i->current; + } + + while (i->next != NULL && + i->next->parent != NULL && + i->next != i->t) { + if (i->next->i < i->next->parent->outDegree - 1) { + i->next = i->next->parent->children[i->next->i + 1]; + return i->current; + } + + i->next = i->next->parent; + } + + i->next = NULL; + return i->current; +} + +TreeNode* tree_preorder_walk_prev(TreeIterator* i) +{ + i->next = i->current; + i->current = i->prev; + + if (i->prev == i->t || i->prev == NULL) { + i->prev = NULL; + } + else if (i->prev->i > 0) { + i->prev = i->prev->parent->children[i->prev->i - 1]; + + while (i->prev->outDegree > 0) { + i->prev = i->prev->children[i->prev->outDegree - 1]; + } + } + else { + i->prev = i->prev->parent; + } + + return i->current; +} + +void tree_postorder_walk(TreeIterator* i, Tree* t) +{ + i->t = t; + i->next = t; + i->current = NULL; + i->prev = NULL; + + while (i->next != NULL && i->next->outDegree > 0) { + i->next = i->next->children[0]; + } +} + +TreeNode* tree_postorder_walk_next(TreeIterator* i) +{ + i->prev = i->current; + i->current = i->next; + + if (i->next == NULL || + i->next->parent == NULL || + i->next == i->t) { + i->next = NULL; + } + else if (i->next->i < i->next->parent->outDegree - 1) { + i->next = i->next->parent->children[i->next->i + 1]; + + while (i->next->outDegree > 0) { + i->next = i->next->children[0]; + } + } + else { + i->next = i->next->parent; + } + + return i->current; +} + +TreeNode* tree_postorder_walk_prev(TreeIterator* i) +{ + i->next = i->current; + i->current = i->prev; + + if (i->prev == NULL) { + return i->current; + } + + if (i->prev->outDegree > 0) { + i->prev = i->prev->children[i->prev->outDegree - 1]; + return i->prev; + } + + while (i->prev->parent != NULL && + i->prev != NULL && + i->prev != i->t) { + if (i->prev ->i > 0) { + i->prev = i->prev->parent->children[i->prev->i - 1]; + return i->prev; + } + + i->prev = i->prev->parent; + } + + i->prev = NULL; + return i->current;; +} diff --git a/src/tree.h b/src/tree.h new file mode 100644 index 0000000..eb6a002 --- /dev/null +++ b/src/tree.h @@ -0,0 +1,467 @@ +/* + +Copyright (c) 2016, Stefan Cloudt + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + + */ + +/** + * @file tree.h + * + * @brief A tree data structure with common functions to be used on a tree. + * + * A tree is an Abstract Data Type containing nodes in a tree structure. Every + * tree has one root node which has no incoming edges. All other nodes are + * connected by one edge to another node where all nodes except the root have + * only 1 incoming edge and zero or more outgoing edges. + */ + +#ifndef ALGORITHM_SORTEDARRAY_H +#define ALGORITHM_SORTEDARRAY_H + +#ifdef __cplusplus +extern "C" { +#endif +/** + * Definition of a TreeNode. A node has a parent node reference which may be + * null, indicating it is the root node. A node might have zero or more child + * nodes. + */ +typedef struct _TreeNode TreeNode; + +/** + * Definition of a Tree. A tree is actually a tree node where the tree node is + * regarded the root of the tree. + */ +typedef TreeNode Tree; + +/** + * A value to store in the tree. + */ +typedef void* TreeNodeValue; + +/** + * Iterator used for iterating the tree's nodes. + */ +typedef struct _TreeIterator TreeIterator; + +/** + * Allocates an tree. + * + * @param data The data to put into the root node. + * @return A newly allocated Tree or NULL on failure. + */ +Tree* tree_alloc(TreeNodeValue data); + +/** + * Frees all nodes of the given tree. + * + * Since a subtree is just a tree it can be freed to. However note that the + * subtree will also be automaticly removed from the parent tree. + * + * @param t The tree to free all nodes of. + */ +void tree_free(Tree* t); + +/** + * Returns the root of t. + * + * @param t The tree to return the root of. + * @return The root of t. + */ +TreeNode* tree_root(Tree* t); + +/** + * Returns the absolute root of node n. The absolute node is defined as the node + * which has no parent. + * + * @param n The node. + * @return The absolute root of n. + */ +TreeNode* tree_abs_root(TreeNode* n); + +/** + * Returns a subtree rooted n. + * + * @param n The root of the new subtree. + * @return The subtree rooted n. + */ +Tree* tree_subtree(TreeNode* n); + +/** + * Returns the data stored inside a node. + * + * @param n The data to return. + * @return The data stored in n. + */ +TreeNodeValue tree_data(TreeNode* n); + +/** + * Sets the data d of node n. + * + * @param n The node to set the data of. + * @param d The data to set. + */ +void tree_set_data(TreeNode* n, TreeNodeValue d); + +/** + * Returns the parent of node n in tree t. + * + * If n is the root of t then NULL is returned. + * + * @param t The tree in which the parent is. + * @param n The node to get the parent of. + * @return The parent node of n in t. Or NULL if n is root of t. + */ +TreeNode* tree_parent(Tree* t, TreeNode* n); + +/** + * Returns the i-th child of n. + * + * @param n The node. + * @param i The offset. + * @return NULL if the child at i does not exists, or the i-th child. + */ +TreeNode* tree_child(TreeNode* n, unsigned int i); + +/** + * Returns the first child of n if any. + * + * @param n The node. + * @return The first child of n if any otherwise NULL. + */ +TreeNode* tree_first_child(TreeNode* n); + +/** + * Returns the last child of n if any. + * + * @param n The node. + * @return The last child of n if any otherwise NULL. + */ +TreeNode* tree_last_child(TreeNode* n); + +/** + * Returns the out degree of node n. + * + * @param n The node. + * @return The out degree. + */ +unsigned int tree_out_degree(TreeNode* n); + +/** + * Returns an array containing the children of node n. Using the function + * @ref tree_out_degree you can get the amount of children a node has. + * + * @param n The node. + * @return A pointer to an array containing the children of node n. If is has no + * children then NULL is returned. + */ +TreeNode** tree_children(TreeNode* n); + +/** + * Returns whether or not node n is a leaf. + * + * @param n The node. + * @return >0 if n is a leaf, <=0 if not. + */ +int tree_is_leaf(TreeNode* n); + +/** + * Returns whether or not node d is a descendent of node n. + * + * @param d The possible descendent node. + * @param n The node. + * @return >0 if d is a descendent of n, <=0 if not. + */ +int tree_is_descendant_of(TreeNode* d, TreeNode* n); + +/** + * Returns whether or not node a is an ancestor of node n. + * + * @param a The possible ancestor node. + * @param n The node. + * @return >0 if a is an ancestor of n, <=0 if not. + */ +int tree_is_ancestor_of(TreeNode* a, TreeNode* n); + +/** + * Returns the depth of node n in t. The depth of a tree is the number of edges + * from this node to the root node. + * + * Note that if n is not inside t then the function will return 0. + * + * @param t The tree. + * @param n The node. + * @return The depth of n in t. + */ +unsigned int tree_depth(Tree* t, TreeNode* n); + +/** + * Returns the level of node n in t. The level of a tree is defined as 1 + the + * depth. + * + * Note that if n is not inside t then the function will return 0. + * + * @param t The tree. + * @param n The node. + * @return The level of n in t. + */ +unsigned int tree_level(Tree* t, TreeNode* n); + +/** + * Returns the height of tree t. The height of a tree is the largest amount of + * edges between the root of t and a leaf. + * + * @param t The tree. + * @return The height of t. + */ +unsigned int tree_height(Tree* t); + +/** + * Returns the height of node n. The height of a node is the longest path + * between the node and a leaf. + * + * @param n The node. + * @return The height of n. + */ +unsigned int tree_height_node(TreeNode* n); + +/** + * Removes node n and all its child nodes from its tree and thereby creating a + * new tree rooted n which is returned. + * + * @param n The node to remove from its parent tree + * @return The subtree created rooted n. + */ +Tree* tree_remove(TreeNode* n); + +/** + * Deletes node n and all its child nodes. This means that the node is removed + * from its parent tree and n is freed from memory. + * + * @param n The node. + * @return >0 on success, <=0 on failure. + */ +void tree_delete(TreeNode* n); + +/** + * Adds a tree t as a subtree of node n. To make sure that every node is only + * part of one tree the node is first removed before it is added to its new + * location. + * + * @param n The node. + * @param t The subtree. + * @return Null on success, or the node which was to be added to the tree. + */ +Tree* tree_add_subtree(TreeNode* n, Tree* t); + +/** + * Adds a child storing data as child of node n. + * + * @param n The node. + * @param data The data. + * @return The newly added child or NULL on failure. + */ +TreeNode* tree_add_child(TreeNode* n, TreeNodeValue data); + +/** + * Inserts a tree t as subtree of node n at offset i of n's children. When t is + * NULL nothing is inserted. The range of i must be 0 <= i <= l, where l is the + * out degree of n. + * + * @param n The node. + * @param t The tree. + * @param i The offset. + * @return NULL on success, or tree t on failure. + */ +Tree* tree_insert_subtree(TreeNode* n, Tree* t, unsigned int i); + +/** + * Inserts a child storing value data as child of node n at offset i of n's + * children. The range of i must be 0 <= i <= l, where l is the + * out degree of n. + * + * @param n The node. + * @param data The data. + * @param i The offset. + * @return The newly inserted child or NULL on failure. + */ +TreeNode* tree_insert_child(TreeNode* n, TreeNodeValue data, unsigned int i); + +/** + * Sets the child at position i of node n's children to tree t. Let l be the + * amount of children then i should be in the range 0 <= i <= l. + * + * @param n The node. + * @param t The tree. + * @param i The offset. + * @return Null on success, or t on failure. + */ +Tree* tree_set_subtree(TreeNode* n, Tree* t, unsigned int i); + +/** + * Sets a child storing value data as child stored at position i of node n's + * children. Let l be the amount of children then i should be in the range of + * 0 <= i <= l. + * + * @param n The node. + * @param data The data. + * @param i The offset. + * @return The newly set child or NULL on failure. + */ +TreeNode* tree_set_child(TreeNode* n, TreeNodeValue data, unsigned int i); + +/** + * Returns the data of the current node of iterator i. + * + * @param i The iterator. + * @return The data of the current node of i. + */ +TreeNodeValue tree_iter_data(TreeIterator* i); + +/** + * Returns whether or not iteration is not finished. + * + * @param i The iterator. + * @return >0 If iteration is not done, <=0 if iteration is done. + */ +int tree_iter_has_next(TreeIterator* i); + +/** + * Returns whether or not iterations is not finished. + * + * @param i The iterator. + * @return >0 If iteration is not done, <=0 if iteration is done. + */ +int tree_iter_has_prev(TreeIterator* i); + +/** + * Allocates an tree iterator. + * + * @return The iterator or NULL on failure. + */ +TreeIterator* tree_iter_alloc(); + +/** + * Frees the iterator from memory. + * + * @param i The iterator to free. + */ +void tree_iter_free(TreeIterator* i); + +/** + * Initializes an iterator to iterate over the leaves of tree t. Starting with + * the first leaf. + * + * @param i The iterator. + * @param t The tree. + */ +void tree_iter_leaves_first(TreeIterator* i, Tree* t); + +/** + * Initializes an iterator to iterate over the leaves of tree t. Starting with + * the last leaf. + * + * @param i The iterator. + * @param t The tree. + */ +void tree_iter_leaves_last(TreeIterator* i, Tree* t); + +/** + * Iterates to the next leaf of iterator i. + * + * @param i The iterator. + * @return The current leaf or NULL if none. + */ +TreeNode* tree_iter_leaves_next(TreeIterator* i); + +/** + * Iterates to the previous leaf of iterator i. + * + * @param i The iterator. + * @return The current leaf or NULL if none. + */ +TreeNode* tree_iter_leaves_prev(TreeIterator* i); + +/** + * Iterates over all parents of node n in tree t starting from the node n and + * ending the root of tree t. + * + * @param i The iterator. + * @param t The tree. + * @param n The node. + */ +void tree_iter_parents(TreeIterator* i, Tree* t, TreeNode* n); + +/** + * Iterate to the next parent of the current node of iterator i. + * + * @param i The iterator. + * @return The current parent, or NULL if none. + */ +TreeNode* tree_iter_parents_next(TreeIterator* i); + +/** + * Initializes an iterator to do a preorder walk over tree t. + * + * @param i The iterator. + * @param t The tree. + */ +void tree_preorder_walk(TreeIterator* i, Tree* t); + +/** + * Iterates to the next node in the preorder walk of iterator i. + * + * @param i The iterator. + * @return The current node or NULL if none. + */ +TreeNode* tree_preorder_walk_next(TreeIterator* i); + +/** + * Iterates to the previous node in the preorder walk of iterator i. + * + * @param i The iterator. + * @return The current node or NULL if none. + */ +TreeNode* tree_preorder_walk_prev(TreeIterator* i); + +/** + * Initializes an iterator to do a postorder walk over tree t. + * + * @param i The iterator. + * @param t The tree. + */ +void tree_postorder_walk(TreeIterator* i, Tree* t); + +/** + * Iterates to the next node in the postorder walk of iterator i. + * + * @param i The iterator. + * @return The current node or NULL if none. + */ +TreeNode* tree_postorder_walk_next(TreeIterator* i); + +/** + * Iterates to the previous node in the postorder walk of iterator i. + * + * @param i The iterator. + * @return The current node or NULL if none. + */ +TreeNode* tree_postorder_walk_prev(TreeIterator* i); +#ifdef __cplusplus +} +#endif +#endif diff --git a/test/Makefile.am b/test/Makefile.am index d01cd7d..df039ab 100644 --- a/test/Makefile.am +++ b/test/Makefile.am @@ -24,7 +24,8 @@ TESTS = \ test-rb-tree \ test-set \ test-trie \ - test-sortedarray + test-sortedarray \ + test-tree check_PROGRAMS = $(TESTS) check_LIBRARIES = libtestframework.a diff --git a/test/test-tree.c b/test/test-tree.c new file mode 100644 index 0000000..1ad34fc --- /dev/null +++ b/test/test-tree.c @@ -0,0 +1,369 @@ +/* + +Copyright (c) 2016, Stefan Cloudt + +Permission to use, copy, modify, and/or distribute this software +for any purpose with or without fee is hereby granted, provided +that the above copyright notice and this permission notice appear +in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL +WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE +AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR +CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, +NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN +CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +) + */ + +#include +#include +#include +#include + +#include "framework.h" +#include "tree.h" + +int vals[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + +Tree* generate_tree() +{ + Tree* t = tree_alloc(&vals[0]); + assert(t != NULL); + + TreeNode* t1 = tree_add_child(t, &vals[1]); + tree_add_child(t1, &vals[2]); + TreeNode* t3 = tree_add_child(t1, &vals[3]); + + int i = 0; + for (i = 4; i <= 6; i++) { + tree_add_child(t3, &vals[i]); + } + + TreeNode* t7 = tree_add_child(t, &vals[7]); + TreeNode* t8 = tree_add_child(t7, &vals[8]); + tree_add_child(t8, &vals[9]); + + return t; +} + +void test_tree_abs_root_r(Tree* t, TreeNode* n) +{ + assert(tree_abs_root(n) == t); + + unsigned int i = 0; + for (i = 0; i < tree_out_degree(n); i++) { + test_tree_abs_root_r(t, tree_child(n, i)); + } +} + +void test_tree_abs_root(void) +{ + Tree* t = generate_tree(); + test_tree_abs_root_r(t, t); + tree_free(t); +} + +void test_tree_is_leaf_r(TreeNode* n) +{ + assert(tree_is_leaf(n) == (tree_out_degree(n) == 0)); + + unsigned int i = 0; + for (i = 0; i < tree_out_degree(n); i++) { + test_tree_is_leaf_r(tree_child(n, i)); + } +} + +void test_tree_is_leaf(void) +{ + Tree* t = generate_tree(); + test_tree_is_leaf_r(t); + tree_free(t); +} + +void test_tree_is_descendant_of_r(Tree* t, TreeNode* n) +{ + TreeNode* p = tree_parent(t, n); + while (p != NULL) { + assert(tree_is_descendant_of(n, p)); + p = tree_parent(t, p); + } + + unsigned int i = 0; + for (i = 0; i < tree_out_degree(n); i++) { + test_tree_is_descendant_of_r(t, tree_child(n, i)); + } +} + +void test_tree_is_descendant_of(void) +{ + Tree* t = generate_tree(); + test_tree_is_descendant_of_r(t, t); + tree_free(t); +} + +void test_tree_is_ancestor_of_r(Tree* t, TreeNode* n) +{ + TreeNode* p = tree_parent(t, n); + while (p != NULL) { + assert(tree_is_ancestor_of(p, n)); + p = tree_parent(t, p); + } + + unsigned int i = 0; + for (i = 0; i < tree_out_degree(n); i++) { + test_tree_is_ancestor_of_r(t, tree_child(n, i)); + } +} + +void test_tree_is_ancestor_of(void) +{ + Tree* t = generate_tree(); + test_tree_is_ancestor_of_r(t, t); + tree_free(t); +} + +void test_tree_depth_level_r(Tree* t, TreeNode* n, unsigned int d) +{ + assert(tree_depth(t, n) == d); + assert(tree_level(t, n) == d + 1); + + unsigned int i; + for (i = 0; i < tree_out_degree(n); i++) { + test_tree_depth_level_r(t, tree_child(n, i), d + 1); + } +} + +void test_tree_depth_level(void) +{ + Tree* t = generate_tree(); + test_tree_depth_level_r(t, t, 0); + tree_free(t); +} + +unsigned int test_tree_height_r(TreeNode* n) +{ + unsigned int h = 0; + unsigned int i; + for (i = 0; i < tree_out_degree(n); i++) { + unsigned int hi = test_tree_height_r(tree_child(n, i)); + h = (h > hi) ? h : hi; + } + + assert(tree_height_node(n) == h); + + return h; +} + +void test_tree_height(void) +{ + Tree* t = generate_tree(); + test_tree_height_r(t); + tree_free(t); +} + +void test_tree_remove(void) +{ + /* test removal of node 3 and 9 */ + Tree* t = generate_tree(); + + /* node 3 */ + TreeNode* t1 = tree_first_child(t); + TreeNode* t3 = tree_last_child(t1); + unsigned int d = tree_out_degree(t1); + t3 = tree_remove(t3); + assert(tree_out_degree(t1) == d - 1); + test_tree_height_r(t); + + /* node 9 */ + TreeNode* t7 = tree_last_child(t); + TreeNode* t8 = tree_last_child(t7); + TreeNode* t9 = tree_last_child(t8); + d = tree_out_degree(t8); + t9 = tree_remove(t9); + assert(tree_out_degree(t8) == d - 1); + test_tree_height_r(t); + + tree_free(t); + tree_free(t3); + tree_free(t9); +} + +void test_tree_add_subtree(void) +{ + /* Remove t3 and add it as child of 9 */ + Tree* t = generate_tree(); + + TreeNode* t1 = tree_first_child(t); + TreeNode* t3 = tree_last_child(t1); + t3 = tree_remove(t3); + + TreeNode* t7 = tree_last_child(t); + TreeNode* t8 = tree_last_child(t7); + TreeNode* t9 = tree_last_child(t8); + tree_add_subtree(t9, t3); + + test_tree_height_r(t); + assert(tree_first_child(t9) == t3); + + tree_free(t); +} + +void test_tree_insert_subtree(void) +{ + Tree* t = generate_tree(); + + TreeNode* t7 = tree_last_child(t); + TreeNode* t1 = tree_first_child(t); + TreeNode* t2 = tree_first_child(t1); + TreeNode* t3 = tree_last_child(t1); + + t7 = tree_remove(t7); + tree_insert_subtree(t1, t7, 1); + + assert(tree_child(t1, 1) == t7); + assert(tree_child(t1, 0) == t2); + assert(tree_child(t1, 2) == t3); + test_tree_height_r(t); + + tree_free(t); +} + +void test_tree_set_subtree(void) +{ + Tree* t = generate_tree(); + + TreeNode* t7 = tree_last_child(t); + TreeNode* t1 = tree_first_child(t); + TreeNode* t2 = tree_first_child(t1); + t7 = tree_remove(t7); + + TreeNode* t3 = tree_set_subtree(t1, t7, 1); + + assert(tree_child(t1, 1) == t7); + assert(tree_child(t1, 0) == t2); + + test_tree_height_r(t); + + tree_free(t); + tree_free(t3); +} + +void test_tree_iter_leaves(void) +{ + Tree* t = generate_tree(); + + int order[] = {2, 4, 5, 6, 9}; + unsigned i = 0; + + TreeIterator* iter = tree_iter_alloc(); + tree_iter_leaves_first(iter, t); + while (tree_iter_has_next(iter)) { + tree_iter_leaves_next(iter); + assert(*((int*) tree_iter_data(iter)) == order[i++]); + } + + tree_iter_leaves_last(iter, t); + i = 4; + while (tree_iter_has_prev(iter)) { + tree_iter_leaves_prev(iter); + assert(*((int*) tree_iter_data(iter)) == order[i--]); + } + + tree_free(t); +} + +void test_tree_iter_parents(void) +{ + Tree* t = generate_tree(); + + TreeNode* t1 = tree_first_child(t); + TreeNode* t3 = tree_last_child(t1); + TreeNode* t4 = tree_first_child(t3); + + int order[] = {4, 3, 1, 0}; + unsigned int i = 0; + TreeIterator* iter = tree_iter_alloc(); + tree_iter_parents(iter, t, t4); + while (tree_iter_has_next(iter)) { + tree_iter_parents_next(iter); + assert(*((int*) tree_iter_data(iter)) == order[i++]); + } + + tree_free(t); +} + +void test_tree_preorder_walk(void) +{ + Tree* t = generate_tree(); + + int order[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; + unsigned i = 0; + + TreeIterator* iter = tree_iter_alloc(); + tree_preorder_walk(iter, t); + while (tree_iter_has_next(iter)) { + tree_preorder_walk_next(iter); + assert(*((int*) tree_iter_data(iter)) == order[i++]); + } + + i = 8; + + while (tree_iter_has_prev(iter)) { + tree_preorder_walk_prev(iter); + assert(*((int*) tree_iter_data(iter)) == order[i--]); + } + + tree_free(t); +} + +void test_tree_postorder_walk(void) +{ + Tree* t = generate_tree(); + + int order[] = {2, 4, 5, 6, 3, 1, 9, 8, 7, 0}; + unsigned i = 0; + + TreeIterator* iter = tree_iter_alloc(); + tree_postorder_walk(iter, t); + while (tree_iter_has_next(iter)) { + tree_postorder_walk_next(iter); + assert(*((int*) tree_iter_data(iter)) == order[i++]); + } + + i = 8; + + while (tree_iter_has_prev(iter)) { + tree_postorder_walk_prev(iter); + assert(*((int*) tree_iter_data(iter)) == order[i--]); + } + + tree_free(t); +} + +static UnitTestFunction tests[] = { + test_tree_abs_root, + test_tree_is_leaf, + test_tree_is_descendant_of, + test_tree_is_ancestor_of, + test_tree_depth_level, + test_tree_height, + test_tree_remove, + test_tree_add_subtree, + test_tree_insert_subtree, + test_tree_set_subtree, + test_tree_iter_leaves, + test_tree_iter_parents, + test_tree_preorder_walk, + test_tree_postorder_walk, + NULL +}; + +int main(int argc, char *argv[]) +{ + run_tests(tests); + + return 0; +}