tree: Adding N-tree module.
This commit is contained in:
parent
546e7c50f1
commit
171c764691
4 changed files with 396 additions and 0 deletions
119
src/tree.c
Normal file
119
src/tree.c
Normal 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
48
src/tree.h
Normal 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 */
|
||||
|
|
@ -21,6 +21,7 @@ fscrawl : $(ROOT)src/fscrawl.o $(addprefix $(ROOT),$(obj-fscrawl))
|
|||
notify : $(addprefix $(ROOT),$(obj-notify))
|
||||
inotify-map : $(addprefix $(ROOT),$(obj-inotify-map))
|
||||
log : $(addprefix $(ROOT),$(obj-log))
|
||||
tree : $(addprefix $(ROOT),$(obj-xalloc)) $(ROOT)src/tree.o
|
||||
str-list : unit.c $(addprefix $(ROOT),$(obj-str-list))
|
||||
|
||||
clean :
|
||||
|
|
|
|||
228
test/t_tree.c
Normal file
228
test/t_tree.c
Normal 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;
|
||||
}
|
||||
Reference in a new issue