Archived
1
0
Fork 0

tree: Adding N-tree module.

This commit is contained in:
Henrik Hautakoski 2011-02-14 08:09:42 +01:00
parent 546e7c50f1
commit 171c764691
4 changed files with 396 additions and 0 deletions

119
src/tree.c Normal file
View file

@ -0,0 +1,119 @@
/* tree.c - N-tree implementation
*
* Copyright (C) 2011 Henrik Hautakoski <henrik@fiktivkod.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Generic implementation of a N-tree
*/
#include "xalloc.h"
#include "tree.h"
struct tree* tree_new() {
return xmallocz(sizeof(struct tree));
}
struct tree* tree_link(struct tree *parent, struct tree *tree) {
if (parent->child) {
struct tree *it = parent->child;
while(it->next)
it = it->next;
it->next = tree;
} else {
parent->child = tree;
}
tree->parent = parent;
return tree;
}
void tree_unlink(struct tree *tree) {
if (tree_is_root(tree))
return;
/* remove the node from the tree */
if (tree->parent->child == tree) {
tree->parent->child = tree->next;
} else {
struct tree *prev = tree->parent->child;
while(prev->next && prev->next != tree)
prev = prev->next;
prev->next = tree->next;
}
/* move the children to node's old parent */
if (tree->child) {
struct tree *it = tree->parent->child;
if (tree->parent->child) {
while(it->next)
it = it->next;
it->next = tree->child;
} else {
tree->parent->child = tree->child;
}
/* Update parent */
for(it = tree->child; it; it = it->next)
it->parent = tree->parent;
}
tree->parent = NULL;
tree->next = NULL;
tree->child = NULL;
}
void tree_move(struct tree *dest, struct tree *src) {
if (src->parent == dest)
/* node are already in place */
return;
/* detach and attach att the new node */
tree_detach(src);
tree_link(dest, src);
}
void tree_detach(struct tree *tree) {
if (tree_is_root(tree))
return;
if (tree->parent->child == tree) {
tree->parent->child = tree->next;
} else if (tree->parent->child) {
struct tree *prev = tree->parent->child;
while(prev->next && prev->next != tree)
prev = prev->next;
prev->next = tree->next;
}
tree->parent = NULL;
tree->next = NULL;
}
void tree_traverse(struct tree *tree, tree_traverse_fn fn, void *data) {
while(tree) {
struct tree *next = tree->next;
fn(tree, data);
if (tree->child)
tree_traverse(tree->child, fn, data);
tree = next;
}
}
size_t tree_parent_count(struct tree *tree) {
size_t count = 0;
if (tree) {
for(; tree->parent; count++)
tree = tree->parent;
}
return count;
}

48
src/tree.h Normal file
View file

@ -0,0 +1,48 @@
/* tree.c - N-tree implementation
*
* Copyright (C) 2011 Henrik Hautakoski <henrik@fiktivkod.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*/
#ifndef __TREE_H
#define __TREE_H
#include <stddef.h>
struct tree {
struct tree *next;
struct tree *parent;
struct tree *child;
};
typedef void (*tree_traverse_fn)(struct tree *tree, void *data);
#define tree_is_root(n) \
((n) && \
(n)->parent == NULL && \
(n)->next == NULL)
#define tree_is_leaf(n) \
((n) && (n)->child == NULL)
#define TREE_INIT { NULL }
struct tree* tree_new();
struct tree* tree_link(struct tree *parent, struct tree *tree);
void tree_unlink(struct tree *tree);
void tree_move(struct tree *dest, struct tree *src);
void tree_detach(struct tree *tree);
void tree_traverse(struct tree *tree, tree_traverse_fn fn, void *data);
size_t tree_parent_count(struct tree *tree);
#endif /* __TREE_H */

View file

@ -21,6 +21,7 @@ fscrawl : $(ROOT)src/fscrawl.o $(addprefix $(ROOT),$(obj-fscrawl))
notify : $(addprefix $(ROOT),$(obj-notify)) notify : $(addprefix $(ROOT),$(obj-notify))
inotify-map : $(addprefix $(ROOT),$(obj-inotify-map)) inotify-map : $(addprefix $(ROOT),$(obj-inotify-map))
log : $(addprefix $(ROOT),$(obj-log)) log : $(addprefix $(ROOT),$(obj-log))
tree : $(addprefix $(ROOT),$(obj-xalloc)) $(ROOT)src/tree.o
str-list : unit.c $(addprefix $(ROOT),$(obj-str-list)) str-list : unit.c $(addprefix $(ROOT),$(obj-str-list))
clean : clean :

228
test/t_tree.c Normal file
View file

@ -0,0 +1,228 @@
#include <assert.h>
#include "../src/tree.h"
void test_link() {
struct tree nodes[6] = { TREE_INIT };
tree_link(&nodes[0], &nodes[1]);
tree_link(&nodes[0], &nodes[2]);
tree_link(&nodes[0], &nodes[3]);
tree_link(&nodes[1], &nodes[4]);
tree_link(&nodes[2], &nodes[5]);
/* check the root node */
assert(nodes[0].parent == NULL);
assert(nodes[0].next == NULL);
assert(nodes[0].child == &nodes[1]);
/* move to depth 2 */
assert(nodes[1].parent == &nodes[0]);
assert(nodes[2].parent == &nodes[0]);
assert(nodes[3].parent == &nodes[0]);
assert(nodes[1].next == &nodes[2]);
assert(nodes[2].next == &nodes[3]);
assert(nodes[3].next == NULL);
assert(nodes[1].child == &nodes[4]);
assert(nodes[2].child == &nodes[5]);
/* move to depth 3 */
assert(nodes[4].parent == &nodes[1]);
assert(nodes[5].parent == &nodes[2]);
assert(nodes[4].next == NULL);
assert(nodes[5].next == NULL);
assert(nodes[4].child == NULL);
assert(nodes[5].child == NULL);
}
void test_unlink() {
struct tree nodes[6] = { TREE_INIT };
tree_link(&nodes[0], &nodes[1]);
tree_link(&nodes[0], &nodes[2]);
tree_link(&nodes[1], &nodes[3]);
tree_link(&nodes[1], &nodes[4]);
tree_link(&nodes[2], &nodes[5]);
/* check the tree */
assert(nodes[0].parent == NULL);
assert(nodes[0].next == NULL);
assert(nodes[0].child == &nodes[1]);
/* move to depth 2 */
assert(nodes[1].parent == &nodes[0]);
assert(nodes[2].parent == &nodes[0]);
assert(nodes[1].next == &nodes[2]);
assert(nodes[2].next == NULL);
assert(nodes[1].child == &nodes[3]);
assert(nodes[2].child == &nodes[5]);
/* move to depth 3 */
assert(nodes[3].parent == &nodes[1]);
assert(nodes[4].parent == &nodes[1]);
assert(nodes[5].parent == &nodes[2]);
assert(nodes[3].next == &nodes[4]);
assert(nodes[4].next == NULL);
assert(nodes[5].next == NULL);
assert(nodes[3].child == NULL);
assert(nodes[4].child == NULL);
assert(nodes[5].child == NULL);
tree_unlink(&nodes[1]);
/* check the new tree */
assert(nodes[0].parent == NULL);
assert(nodes[0].next == NULL);
assert(nodes[0].child == &nodes[2]);
/* move to depth 2 */
assert(nodes[2].parent == &nodes[0]);
assert(nodes[3].parent == &nodes[0]);
assert(nodes[4].parent == &nodes[0]);
assert(nodes[2].next == &nodes[3]);
assert(nodes[3].next == &nodes[4]);
assert(nodes[4].next == NULL);
assert(nodes[2].child == &nodes[5]);
assert(nodes[3].child == NULL);
assert(nodes[4].child == NULL);
/* move to depth 3 */
assert(nodes[5].parent == &nodes[2]);
assert(nodes[5].next == NULL);
assert(nodes[5].child == NULL);
}
void test_detach() {
struct tree nodes[6] = { TREE_INIT };
tree_link(&nodes[0], &nodes[1]);
tree_link(&nodes[0], &nodes[2]);
tree_link(&nodes[1], &nodes[3]);
tree_link(&nodes[1], &nodes[4]);
tree_link(&nodes[2], &nodes[5]);
/* check the tree */
assert(nodes[0].parent == NULL);
assert(nodes[0].next == NULL);
assert(nodes[0].child == &nodes[1]);
/* move to depth 2 */
assert(nodes[1].parent == &nodes[0]);
assert(nodes[2].parent == &nodes[0]);
assert(nodes[1].next == &nodes[2]);
assert(nodes[2].next == NULL);
assert(nodes[1].child == &nodes[3]);
assert(nodes[2].child == &nodes[5]);
/* move to depth 3 */
assert(nodes[3].parent == &nodes[1]);
assert(nodes[4].parent == &nodes[1]);
assert(nodes[5].parent == &nodes[2]);
assert(nodes[3].next == &nodes[4]);
assert(nodes[4].next == NULL);
assert(nodes[5].next == NULL);
assert(nodes[3].child == NULL);
assert(nodes[4].child == NULL);
assert(nodes[5].child == NULL);
tree_detach(&nodes[1]);
/* check the tree */
assert(nodes[0].parent == NULL);
assert(nodes[0].next == NULL);
assert(nodes[0].child == &nodes[2]);
/* move to depth 2 */
assert(nodes[2].parent == &nodes[0]);
assert(nodes[2].next == NULL);
assert(nodes[2].child == &nodes[5]);
/* move to depth 3 */
assert(nodes[5].parent == &nodes[2]);
assert(nodes[5].next == NULL);
assert(nodes[5].child == NULL);
/* detached tree */
assert(nodes[1].parent == NULL);
assert(nodes[1].next == NULL);
assert(nodes[1].child == &nodes[3]);
assert(nodes[3].parent == &nodes[1]);
assert(nodes[4].parent == &nodes[1]);
assert(nodes[3].next == &nodes[4]);
assert(nodes[4].next == NULL);
assert(nodes[3].child == NULL);
assert(nodes[4].child == NULL);
}
void test_move() {
struct tree nodes[7] = { TREE_INIT };
tree_link(&nodes[0], &nodes[1]);
tree_link(&nodes[0], &nodes[2]);
tree_link(&nodes[0], &nodes[3]);
tree_link(&nodes[1], &nodes[4]);
tree_link(&nodes[2], &nodes[5]);
tree_link(&nodes[2], &nodes[6]);
tree_move(&nodes[5], &nodes[1]);
assert(nodes[0].parent == NULL);
assert(nodes[0].next == NULL);
assert(nodes[0].child == &nodes[2]);
assert(nodes[3].parent == &nodes[0]);
assert(nodes[2].parent == &nodes[0]);
assert(nodes[2].next == &nodes[3]);
assert(nodes[3].next == NULL);
assert(nodes[2].child == &nodes[5]);
assert(nodes[3].child == NULL);
assert(nodes[5].parent == &nodes[2]);
assert(nodes[6].parent == &nodes[2]);
assert(nodes[5].next == &nodes[6]);
assert(nodes[6].next == NULL);
assert(nodes[5].child == &nodes[1]);
assert(nodes[6].child == NULL);
assert(nodes[1].parent == &nodes[5]);
assert(nodes[1].next == NULL);
assert(nodes[1].child == &nodes[4]);
assert(nodes[4].parent == &nodes[1]);
assert(nodes[4].next == NULL);
assert(nodes[4].child == NULL);
}
void test_parent_count() {
struct tree nodes[6] = { TREE_INIT };
tree_link(&nodes[0], &nodes[1]);
tree_link(&nodes[0], &nodes[2]);
tree_link(&nodes[1], &nodes[3]);
tree_link(&nodes[1], &nodes[4]);
tree_link(&nodes[2], &nodes[5]);
assert(tree_parent_count(&nodes[5]) == 2);
}
int main() {
test_link();
test_unlink();
test_detach();
test_move();
test_parent_count();
return 0;
}