diff --git a/configure.ac b/configure.ac index 0459f62..0e66f70 100644 --- a/configure.ac +++ b/configure.ac @@ -63,5 +63,6 @@ AC_CONFIG_FILES([Makefile src/session/Makefile src/socket/Makefile src/stream/Makefile + src/tree/Makefile tests/Makefile]) AC_OUTPUT diff --git a/include/hash/hash.h b/include/hash/hash.h index 1ddcf2e..5f67a8b 100644 --- a/include/hash/hash.h +++ b/include/hash/hash.h @@ -26,10 +26,11 @@ #include #include "class.h" +#include "tree.h" CLASS(Hash) { - void * root; + Tree root; }; void * hashAdd(Hash, void *); diff --git a/include/tree.h b/include/tree.h new file mode 100644 index 0000000..49d9154 --- /dev/null +++ b/include/tree.h @@ -0,0 +1,138 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __TREE_H__ +#define __TREE_H__ + +#include "class.h" + +#define TREE_RIGHT(node) (NULL!=(node)?(node)->right:NULL) +#define TREE_LEFT(node) (NULL!=(node)?(node)->left:NULL) +#define TREE_PARENT(node) (NULL!=(node)?(node)->parent:NULL) + +#define TREE_CHILD(node) \ + (NULL==TREE_RIGHT((node))?TREE_LEFT((node)):TREE_RIGHT((node))) + +#define TREE_RIGHT_LEFT(node) \ + (NULL!=TREE_RIGHT((node))?TREE_LEFT(TREE_RIGHT((node))):NULL) + +#define TREE_LEFT_RIGHT(node) \ + (NULL!=TREE_LEFT((node))?TREE_RIGHT(TREE_LEFT((node))):NULL) + +#define TREE_SIBLING(node) \ + (NULL!=TREE_PARENT((node))? \ + ((node)==TREE_PARENT((node))->left? \ + TREE_PARENT((node))->right: \ + TREE_PARENT((node))->left): \ + NULL) + +#define TREE_GRANDPARENT(node) \ + (NULL!=TREE_PARENT((node))?TREE_PARENT((node))->parent:NULL) + +#define TREE_UNCLE(node) \ + (NULL!=TREE_GRANDPARENT((node))? \ + (TREE_PARENT((node))==TREE_GRANDPARENT((node))->left? \ + TREE_GRANDPARENT((node))->right: \ + TREE_GRANDPARENT((node))->left): \ + NULL) + +#define TREE_ROTATE_LEFT(root, node) \ + do { \ + if (NULL != TREE_RIGHT_LEFT((node))) { \ + TREE_RIGHT_LEFT((node))->parent = (node); \ + } \ + TREE_RIGHT((node))->left = (node); \ + if (NULL != TREE_PARENT((node))) { \ + if (TREE_PARENT((node))->left==(node)) { \ + TREE_PARENT((node))->left = (node)->right; \ + } else { \ + TREE_PARENT((node))->right = (node)->right; \ + } \ + } else { \ + *(root) = (node)->right; \ + } \ + (node)->right = TREE_RIGHT_LEFT((node)); \ + (node)->parent = (node)->right; \ + TREE_RIGHT((node))->parent = (node)->parent; \ + } while(0) + +#define TREE_ROTATE_RIGHT(root, node) \ + do { \ + if (NULL != TREE_LEFT_RIGHT((node))) { \ + TREE_LEFT_RIGHT((node))->parent = (node); \ + } \ + TREE_LEFT((node))->right = (node); \ + if (NULL != TREE_PARENT((node))) { \ + if (TREE_PARENT((node))->left==(node)) { \ + TREE_PARENT((node))->left = (node)->left; \ + } else { \ + TREE_PARENT((node))->right = (node)->left; \ + } \ + } else { \ + *(root) = (node)->left; \ + } \ + TREE_LEFT((node))->parent = (node)->parent; \ + (node)->left = TREE_LEFT_RIGHT((node)); \ + (node)->parent = (node)->right; \ + } while(0) + +#define TREE_REPLACE_NODE(root, node1, node2) \ + do { \ + if (NULL != TREE_PARENT((node1))) { \ + if ((node1) == TREE_PARENT((node1))->left) { \ + TREE_PARENT((node1))->left = (node2); \ + } else { \ + TREE_PARENT((node1))->right = (node2); \ + } \ + } else { \ + *(root) = (node2); \ + } \ + if (NULL != (node2)) { \ + (node2)->parent = (node1)->parent; \ + } \ + } while(0) + + +enum rbColor {rbBlack=1, rbRed=2}; + +CLASS(Tree) { + void * data; + + enum rbColor color; + + Tree parent; + Tree left; + Tree right; +}; + +typedef int (*TreeComp)(const void *, const void *); +typedef void (*TreeAction)(const void *, const int); + +void * treeFind(Tree, const void *, TreeComp); +void * treeInsert(Tree *, const void *, TreeComp); +void * treeDelete(Tree *, const void *, TreeComp); +void treeWalk(Tree, TreeAction); +void treeDestroy(Tree *, TreeAction); + +#endif // __TREE_H__ + +// vim: set ts=4 sw=4: diff --git a/src/Makefile.am b/src/Makefile.am index e8dc1d5..761ec46 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -21,7 +21,8 @@ LIBS = ./http/libhttp.a \ ./server/libserver.a \ ./session/libsession.a \ ./socket/libsocket.a \ - ./stream/libstream.a + ./stream/libstream.a \ + ./tree/libtree.a AM_CFLAGS = -Wall -I ../include/ @@ -33,4 +34,4 @@ taskrambler_LDADD = $(LIBS) -lrt -lssl -lldap #taskrambler_LDFLAGS = $(COVERAGE_LDFLAGS) SUBDIRS = asset auth cbuf class hash queue http \ - logger server session socket stream + logger server session socket stream tree diff --git a/src/asset/asset.c b/src/asset/asset.c index 2aacc41..2096a81 100644 --- a/src/asset/asset.c +++ b/src/asset/asset.c @@ -20,10 +20,6 @@ * along with this program. If not, see . */ -// for debug -#include - - #include // for mmap @@ -105,9 +101,6 @@ assetCtor(void * _this, va_list * params) return -1; } - printf("DEBUG file mapped from %p to %p\n", - this->data, this->data + this->size); - this->ref_count = 1; return 0; diff --git a/src/asset/pool.c b/src/asset/pool.c index 1c07e20..6fb6d1c 100644 --- a/src/asset/pool.c +++ b/src/asset/pool.c @@ -20,9 +20,6 @@ * along with this program. If not, see . */ -// for debugging -#include - // for size_t #include @@ -47,8 +44,6 @@ assetPoolGet(const char * path, size_t npath) { Asset asset = NULL; - printf("DEBUG: pool get asset --%s--\n", path); - if (NULL == asset_pool) { asset_pool = new(Hash); } else { @@ -57,12 +52,9 @@ assetPoolGet(const char * path, size_t npath) if (NULL == asset) { asset = new(Asset, path, npath); - printf("DEBUG create asset %p\n", asset); hashAdd(asset_pool, asset); } else { - printf("DEBUG found asset %p\n", asset); asset->ref_count++; - printf("DEBUG increase ref_count to %zu\n", asset->ref_count); } return asset; @@ -71,19 +63,20 @@ assetPoolGet(const char * path, size_t npath) size_t assetPoolRelease(Asset asset) { - printf("DEBUG: pool release asset --%s--\n", asset->fname); - if (asset->ref_count > 1) { asset->ref_count--; - printf("DEBUG decrease ref_count to %zu\n", asset->ref_count); return asset->ref_count; } if (NULL != asset) { Asset found = (Asset)hashDelete( asset_pool, asset->fname, asset->nfname); - printf("DEBUG delete %p, parent was %p\n", asset, found); - delete(asset); + + if (found == asset) { + delete(found); + } else { + // this should never happen....error log... + } } return 0; diff --git a/src/hash/add.c b/src/hash/add.c index 7613034..feb287f 100644 --- a/src/hash/add.c +++ b/src/hash/add.c @@ -30,24 +30,35 @@ inline int hashAddComp(const void * a, const void * b) { - return hashableGetHash((void*)b) - hashableGetHash((void*)a); + unsigned long hash_a = hashableGetHash((void*)a); + unsigned long hash_b = hashableGetHash((void*)b); + + if (hash_a < hash_b) { + return -1; + } + + if (hash_a > hash_b) { + return 1; + } + + return 0; } void * hashAdd(Hash this, void * operand) { - void * found = tsearch(operand, &(this->root), hashAddComp); + void * found = treeInsert(&this->root, operand, hashAddComp); if (NULL == found) { return NULL; } - if (operand != *(void**)found) { - hashableHandleDouble(*(void**)found, operand); + if (operand != found) { + hashableHandleDouble(found, operand); delete(operand); } - return *(void**)found; + return found; } // vim: set ts=4 sw=4: diff --git a/src/hash/delete.c b/src/hash/delete.c index cadcf31..503e164 100644 --- a/src/hash/delete.c +++ b/src/hash/delete.c @@ -20,9 +20,6 @@ * along with this program. If not, see . */ -#include - -#include #include #include "asset.h" @@ -34,59 +31,26 @@ inline int hashDeleteComp(const void * a, const void * b) { - if (_Asset == GET_CLASS(b)) { - Asset data = (Asset)b; - printf("DEBUG: search asset hash: %lu\n", - *(const unsigned long*)a); - printf("DEBUG: found: %lu, key: %s\n", - data->hash, data->fname); - } - - return hashableGetHash((void*)b) - *(const unsigned long*)a; -} - -void -action(const void *nodep, const VISIT which, const int depth) -{ - void * datap = *(void **)nodep; - - if (_Asset == GET_CLASS(datap)) { - Asset data = (Asset)datap; + unsigned long hash_a = hashableGetHash((void*)a); - switch (which) { - case preorder: - break; - case postorder: - printf("DEBUG: %s(%lu) => %p\n", data->fname, data->hash, data); - break; - case endorder: - break; - case leaf: - printf("DEBUG: %s(%lu) => %p\n", data->fname, data->hash, data); - break; - } + if (hash_a < *(const unsigned long*)b) { + return -1; + } + + if (hash_a > *(const unsigned long*)b) { + return 1; } + + return 0; } void * hashDelete(Hash this, const char * search, size_t nsearch) { - unsigned long hash = sdbm((const unsigned char *)search, nsearch); - void * found = NULL; - int count = 0; + unsigned long hash = sdbm((const unsigned char *)search, nsearch); + void * found = NULL; - twalk(this->root, action); - while (found == NULL && count < 3) { - found = tdelete(&hash, &(this->root), hashDeleteComp); - if (found == NULL) { - puts("DEBUG: !!!!! NOT FOUND !!!!!!!"); - void * found = hashGet(this, search, nsearch); - printf("DEBUG: find results in %p\n", found); - } - count++; - } - puts("==="); - twalk(this->root, action); + found = treeDelete(&(this->root), &hash, hashDeleteComp); return found; } diff --git a/src/hash/each.c b/src/hash/each.c index e953af8..be1c1bc 100644 --- a/src/hash/each.c +++ b/src/hash/each.c @@ -29,11 +29,9 @@ static void (*cb)(const void*); static inline void -walk(const void * node, const VISIT which, const int depth) +walk(const void * node, const int depth) { - if (endorder == which || leaf == which) { - cb(*(void**)node); - } + cb(node); } void @@ -41,7 +39,7 @@ hashEach(Hash this, void (*callback)(const void*)) { cb = callback; - twalk(this->root, walk); + treeWalk(this->root, walk); } // vim: set ts=4 sw=4: diff --git a/src/hash/get.c b/src/hash/get.c index cebf06b..29a0096 100644 --- a/src/hash/get.c +++ b/src/hash/get.c @@ -26,6 +26,7 @@ #include #include "hash.h" +#include "tree.h" #include "utils/hash.h" static @@ -33,16 +34,26 @@ inline int hashGetComp(const void * a, const void * b) { - return hashableGetHash((void*)b) - *(const unsigned long*)a; + unsigned long hash_a = hashableGetHash((void*)a); + + if (hash_a < *(const unsigned long*)b) { + return -1; + } + + if (hash_a > *(const unsigned long*)b) { + return 1; + } + + return 0; } void * hashGet(Hash this, const char * search, size_t nsearch) { - unsigned long hash = sdbm((const unsigned char *)search, nsearch); - void ** found = tfind(&hash, &(this->root), hashGetComp); + unsigned long hash = sdbm((const unsigned char *)search, nsearch); + void * found = treeFind(this->root, &hash, hashGetComp); - return (NULL != found)? *found : NULL; + return found; } // vim: set ts=4 sw=4: diff --git a/src/hash/hash.c b/src/hash/hash.c index ba8cba2..da4cf20 100644 --- a/src/hash/hash.c +++ b/src/hash/hash.c @@ -38,7 +38,7 @@ hashCtor(void * _this, va_list * params) static inline void -tDelete(void * node) +tDelete(const void * node, const int depth) { delete(node); } @@ -49,12 +49,7 @@ hashDtor(void * _this) { Hash this = _this; - /** - * this is a GNU extension...anyway on most non - * GNUish systems i would not use tsearch anyway - * as the trees will be unbalanced. - */ - tdestroy(this->root, tDelete); + treeDestroy(&this->root, tDelete); } INIT_IFACE(Class, hashCtor, hashDtor, NULL); diff --git a/src/rbtree.c b/src/rbtree.c index a73704b..f997346 100644 --- a/src/rbtree.c +++ b/src/rbtree.c @@ -789,8 +789,8 @@ main(int argc, char * argv[]) traverse(root, printElement); puts(""); - post(root, cleanup); - +// post(root, cleanup); +// return 0; } diff --git a/src/rbtree2.c b/src/rbtree2.c new file mode 100644 index 0000000..2d60e81 --- /dev/null +++ b/src/rbtree2.c @@ -0,0 +1,144 @@ +#include + +#include "class.h" +#include "commons.h" +#include "utils/memory.h" + +#include "tree.h" + +#define NVALUES 10 + +int +insertCompare(const void * tval, const void * search) +{ + return *(const int *)tval - *(const int *)search; +} + +void +printNode(const void * _node, const int depth) +{ + //Tree node = (Tree)_node; + //int value = *(int *)node->data; + int value = *(int *)_node; + int i; + + printf("%010d(%02d)", value, depth); + + // printf("%s %010d(%02d)", + // (node->color==rbRed)?"R":"B", + // value, + // depth); + for (i=0; i. + */ + +#include "tree.h" + +Tree inOrderSuccessor(Tree); +void treeRotateLeft(Tree *, Tree); +void treeRotateRight(Tree *, Tree); + + +void * +treeDelete(Tree * this, const void * search, TreeComp comp) +{ + Tree node = *this; + + void * data; + + /* + * first search for it and if its found return the data + * and we are done... + */ + while (NULL != node) { + int comparison = comp(node->data, search); + + if (0 < comparison) { + node = TREE_LEFT(node); + continue; + } + + if (0 > comparison) { + node = TREE_RIGHT(node); + continue; + } + + if (0 == comparison) { + break; + } + } + + /* + * nothing was found...return NULL to indicate this. + */ + if (NULL == node) { + return NULL; + } + + /* + * we found an element, store its data pointer as we are + * up to delete it. + */ + data = node->data; + + /* + * now remove the element. + */ + + /* + * if we have two children replace data with the one from + * out inOrderSuccessor and remove the inOrderSuccessor. + */ + if (NULL != TREE_LEFT(node) && NULL != TREE_RIGHT(node)) { + Tree successor = inOrderSuccessor(node); + + node->data = successor->data; + node = successor; + } + + { + Tree child = TREE_CHILD(node); + + /* + * if we still have one child replace ourself with it. + */ + TREE_REPLACE_NODE(this, node, child); + + /* + * and finally delete the node...and prepare ourselfs + * for rebalancing. + */ + if (rbBlack == node->color) { + if (NULL != child && rbRed == child->color) { + child->color = rbBlack; + delete(node); + return data; + } else { + if (NULL != child) { + node = child; + } else { + node->color = rbBlack; + node->left = NULL; + node->right = NULL; + } + } + } else { + delete(node); + return data; + } + } + + /* + * now comes rebalancing...note that if we came to this point + * the node is still not deleted. + * This is because I am not sure if it is needed during the + * rebalancing process...(this does not make much sense, but + * to be honest I don't know now.) + */ + while(1) { + // case 1 + if (NULL == TREE_PARENT(node)) { + break; + } + + // case 2 + if (NULL != TREE_SIBLING(node) + && rbRed == TREE_SIBLING(node)->color) { + + TREE_PARENT(node)->color = rbRed; + TREE_SIBLING(node)->color = rbBlack; + + if (NULL != TREE_PARENT(node)->right && + node != TREE_PARENT(node)->right) { + + //TREE_ROTATE_LEFT(this, TREE_PARENT(node)); + treeRotateLeft(this, TREE_PARENT(node)); + + } else { + + //TREE_ROTATE_RIGHT(this, TREE_PARENT(node)); + treeRotateRight(this, TREE_PARENT(node)); + + } + } + + // case 3 / 4 + if (NULL == TREE_SIBLING(node) + || (rbBlack == TREE_SIBLING(node)->color + && (NULL == TREE_SIBLING(node)->left + || rbBlack == TREE_SIBLING(node)->left->color) + && (NULL == TREE_SIBLING(node)->right + || rbBlack == TREE_SIBLING(node)->right->color))) { + + if (NULL != TREE_SIBLING(node)) { + TREE_SIBLING(node)->color = rbRed; + } + + + /* + * this is the point where during the balancing our tree + * node can be finally deleted. + */ + if (rbBlack == TREE_PARENT(node)->color) { + // case 3 + Tree parent = node->parent; + delete(node); + node = parent; + continue; + } else { + // case 4 + TREE_PARENT(node)->color = rbBlack; + delete(node); + break; + } + } + + // case 5 + if (NULL != TREE_SIBLING(node) + && rbBlack == TREE_SIBLING(node)->color) { + + if (node == TREE_PARENT(node)->left + && (NULL == TREE_SIBLING(node)->right + || rbBlack == TREE_SIBLING(node)->right->color) + && (NULL != TREE_SIBLING(node)->left + && rbRed == TREE_SIBLING(node)->left->color)) { + + TREE_SIBLING(node)->color = rbRed; + TREE_SIBLING(node)->left->color = rbBlack; + + //TREE_ROTATE_RIGHT(this, TREE_SIBLING(node)); + treeRotateRight(this, TREE_SIBLING(node)); + + } else if (node == TREE_PARENT(node)->right + && (NULL == TREE_SIBLING(node)->left + || rbBlack == TREE_SIBLING(node)->left->color) + && (NULL != TREE_SIBLING(node)->right + && rbRed == TREE_SIBLING(node)->right->color)) { + + TREE_SIBLING(node)->color = rbRed; + TREE_SIBLING(node)->right->color = rbBlack; + + //TREE_ROTATE_LEFT(this, TREE_SIBLING(node)); + treeRotateLeft(this, TREE_SIBLING(node)); + } + } + + // case 6 + if (NULL != TREE_SIBLING(node)) { + TREE_SIBLING(node)->color = TREE_PARENT(node)->color; + } + + if (NULL != node && NULL != TREE_PARENT(node)) { + TREE_PARENT(node)->color = rbBlack; + + if (NULL != TREE_PARENT(node)->right + && node != TREE_PARENT(node)->right) { + + if (NULL != TREE_SIBLING(node)->right) { + TREE_SIBLING(node)->right->color = rbBlack; + } + //TREE_ROTATE_LEFT(this, TREE_PARENT(node)); + treeRotateLeft(this, TREE_PARENT(node)); + } else { + if (NULL != TREE_SIBLING(node)->left) { + TREE_SIBLING(node)->left->color = rbBlack; + } + //TREE_ROTATE_RIGHT(this, TREE_PARENT(node)); + treeRotateRight(this, TREE_PARENT(node)); + } + } + + break; + } + + /* + * not sure if deleting here is correct. + */ + return data; +} + +// vim: set ts=4 sw=4: diff --git a/src/tree/destroy.c b/src/tree/destroy.c new file mode 100644 index 0000000..8a6015e --- /dev/null +++ b/src/tree/destroy.c @@ -0,0 +1,84 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "tree.h" + +void +treeDestroy(Tree * this, TreeAction action) +{ + Tree previous = * this; + Tree node = * this; + int depth = 1; + + /* + * I think this has something like O(n+log(n)) on a ballanced + * tree because I have to traverse back the rightmost leaf to + * the root to get a break condition. + */ + while (NULL != node) { + /* + * If we come from the right so nothing and go to our + * next parent. + */ + if ((NULL == TREE_LEFT(node) && NULL == TREE_RIGHT(node)) + || previous == TREE_RIGHT(node)) { + + Tree parent = TREE_PARENT(node); + + action(node->data, depth); + + previous = node; + delete(node); + node = parent; + depth--; + + continue; + } + + if ((NULL == TREE_LEFT(node) || previous == TREE_LEFT(node))) { + /* + * If there are no more elements to the left or we + * came from the left, process data. + */ + previous = node; + + if (NULL != TREE_RIGHT(node)) { + node = TREE_RIGHT(node); + depth++; + } else { + node = TREE_PARENT(node); + depth--; + } + } else { + /* + * if there are more elements to the left go there. + */ + previous = node; + node = TREE_LEFT(node); + depth++; + } + } + + *this = NULL; +} + +// vim: set ts=4 sw=4: diff --git a/src/tree/find.c b/src/tree/find.c new file mode 100644 index 0000000..535a70a --- /dev/null +++ b/src/tree/find.c @@ -0,0 +1,49 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "tree.h" + +void * +treeFind(Tree this, const void * search, TreeComp comp) +{ + while (NULL != this) { + int comparison = comp(this->data, search); + + if (0 < comparison) { + this = TREE_LEFT(this); + continue; + } + + if (0 > comparison) { + this = TREE_RIGHT(this); + continue; + } + + if (0 == comparison) { + break; + } + } + + return NULL != this ? this->data : NULL; +} + +// vim: set ts=4 sw=4: diff --git a/src/tree/inOrderSuccessor.c b/src/tree/inOrderSuccessor.c new file mode 100644 index 0000000..52c36f2 --- /dev/null +++ b/src/tree/inOrderSuccessor.c @@ -0,0 +1,37 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "tree.h" + +Tree +inOrderSuccessor(Tree this) +{ + this = TREE_RIGHT(this); + + while (NULL != TREE_LEFT(this)) { + this = TREE_LEFT(this); + } + + return this; +} + +// vim: set ts=4 sw=4: diff --git a/src/tree/insert.c b/src/tree/insert.c new file mode 100644 index 0000000..f5d4c46 --- /dev/null +++ b/src/tree/insert.c @@ -0,0 +1,152 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "tree.h" + +void treeRotateLeft(Tree *, Tree); +void treeRotateRight(Tree *, Tree); + +void * +treeInsert(Tree * this, const void * search, TreeComp comp) +{ + Tree node = *this; + Tree new_node = NULL; + + /* + * insert the node or return the one in tree if comparison + * succeeds. + */ + if (NULL == node) { + /* + * if the root is NULL we simple add the element and set + * node to it. + */ + *this = node = new_node = new(Tree, search); + } else { + /* + * first search for it and if its found return the data + * and we are done... + */ + int comparison; + + while (NULL != node) { + comparison = comp(node->data, search); + + if (0 < comparison) { + if (NULL != TREE_LEFT(node)) { + node = TREE_LEFT(node); + continue; + } else { + break; + } + } + + if (0 > comparison) { + if (NULL != TREE_RIGHT(node)) { + node = TREE_RIGHT(node); + continue; + } else { + break; + } + } + + if (0 == comparison) { + return node->data; + } + } + + /* + * as we have not found it now add a new element. + */ + if (0 < comparison) { + node->left = new(Tree, search); + TREE_LEFT(node)->parent = node; + node = new_node = TREE_LEFT(node); + } else { + node->right = new(Tree, search); + TREE_RIGHT(node)->parent = node; + node = new_node = TREE_RIGHT(node); + } + } + + /* + * we expect node not to be NULL and pointing to our + * new node at this point...now rabalance the tree + */ + while (1) { + // case 1 + if (NULL == TREE_PARENT(node)) { + node->color = rbBlack; + break; + } + + // case 2 + if (rbBlack == TREE_PARENT(node)->color) { + break; + } + + // case 3 + if (NULL != TREE_UNCLE(node) && rbRed == TREE_UNCLE(node)->color) { + TREE_PARENT(node)->color = rbBlack; + TREE_UNCLE(node)->color = rbBlack; + TREE_GRANDPARENT(node)->color = rbRed; + + node = TREE_GRANDPARENT(node); + continue; + } + + // case 4 + if (node == TREE_PARENT(node)->right + && TREE_PARENT(node) == TREE_GRANDPARENT(node)->left) { + + //TREE_ROTATE_LEFT(this, TREE_PARENT(node)); + treeRotateLeft(this, TREE_PARENT(node)); + node = TREE_LEFT(node); + + } else if (node == TREE_PARENT(node)->left + && TREE_PARENT(node) == TREE_GRANDPARENT(node)->right) { + + //TREE_ROTATE_RIGHT(this, TREE_PARENT(node)); + treeRotateRight(this, TREE_PARENT(node)); + node = TREE_RIGHT(node); + + } + + // case 5 + TREE_PARENT(node)->color = rbBlack; + TREE_GRANDPARENT(node)->color = rbRed; + + if (node == TREE_PARENT(node)->left) { + //TREE_ROTATE_RIGHT(this, TREE_GRANDPARENT(node)); + treeRotateRight(this, TREE_GRANDPARENT(node)); + } else { + //TREE_ROTATE_LEFT(this, TREE_GRANDPARENT(node)); + treeRotateLeft(this, TREE_GRANDPARENT(node)); + } + + break; + } + + return new_node->data; +} + +// vim: set ts=4 sw=4: diff --git a/src/tree/rotateLeft.c b/src/tree/rotateLeft.c new file mode 100644 index 0000000..d14508d --- /dev/null +++ b/src/tree/rotateLeft.c @@ -0,0 +1,51 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "tree.h" + +void +treeRotateLeft(Tree * this, Tree node) +{ + Tree rightChild = TREE_RIGHT(node); + Tree rcLeftSub = TREE_RIGHT_LEFT(node); + + rightChild->left = node; + rightChild->parent = TREE_PARENT(node); + node->right = rcLeftSub; + if (NULL != rcLeftSub) { + rcLeftSub->parent = node; + } + + if (NULL != TREE_PARENT(node)) { + if (TREE_PARENT(node)->left == node) { + TREE_PARENT(node)->left = rightChild; + } else { + TREE_PARENT(node)->right = rightChild; + } + } else { + *this = rightChild; + } + + node->parent = rightChild; +} + +// vim: set ts=4 sw=4: diff --git a/src/tree/rotateRight.c b/src/tree/rotateRight.c new file mode 100644 index 0000000..75c29a9 --- /dev/null +++ b/src/tree/rotateRight.c @@ -0,0 +1,51 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "tree.h" + +void +treeRotateRight(Tree * this, Tree node) +{ + Tree leftChild = TREE_LEFT(node); + Tree lcRightSub = TREE_LEFT_RIGHT(node); + + leftChild->right = node; + leftChild->parent = TREE_PARENT(node); + node->left = lcRightSub; + if (NULL != lcRightSub) { + lcRightSub->parent = node; + } + + if (NULL != TREE_PARENT(node)) { + if (TREE_PARENT(node)->left == node) { + TREE_PARENT(node)->left = leftChild; + } else { + TREE_PARENT(node)->right = leftChild; + } + } else { + *this = leftChild; + } + + node->parent = leftChild; +} + +// vim: set ts=4 sw=4: diff --git a/src/tree/tree.c b/src/tree/tree.c new file mode 100644 index 0000000..cc3bcd1 --- /dev/null +++ b/src/tree/tree.c @@ -0,0 +1,54 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#define _GNU_SOURCE + +#include + +#include "tree.h" +#include "class.h" + +static +int +treeCtor(void * _this, va_list * params) +{ + Tree this = _this; + + this->data = va_arg(*params, void *); + this->color = rbRed; + this->parent = NULL; + this->left = NULL; + this->right = NULL; + + return 0; +} + +static +void +treeDtor(void * _this) +{ +} + +INIT_IFACE(Class, treeCtor, treeDtor, NULL); +CREATE_CLASS(Tree, NULL, IFACE(Class)); + +// vim: set ts=4 sw=4: diff --git a/src/tree/walk.c b/src/tree/walk.c new file mode 100644 index 0000000..992e742 --- /dev/null +++ b/src/tree/walk.c @@ -0,0 +1,59 @@ +/** + * \file + * + * \author Georg Hopp + * + * \copyright + * Copyright © 2012 Georg Hopp + * + * 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. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "tree.h" + +void +treeWalk(Tree this, TreeAction action) +{ + Tree previous = this; + Tree node = this; + int depth = 1; + + while (NULL != node) { + if (previous == TREE_RIGHT(node)) { + previous = node; + node = node->parent; + depth--; + continue; + } + + if (NULL == TREE_LEFT(node) || previous == TREE_LEFT(node)) { + action(node->data, depth); + previous = node; + + if (NULL != TREE_RIGHT(node)) { + node = TREE_RIGHT(node); + depth++; + } else { + node = TREE_PARENT(node); + depth--; + } + } else { + previous = node; + node = TREE_LEFT(node); + depth++; + } + } +} + +// vim: set ts=4 sw=4: diff --git a/src/utils/memory.c b/src/utils/memory.c index bd71c05..692ce87 100644 --- a/src/utils/memory.c +++ b/src/utils/memory.c @@ -54,14 +54,12 @@ #include #include "utils/memory.h" +#include "tree.h" #define PAGE_SIZE = 32 -enum rbColor {rbBlack=1, rbRed=2}; - - struct memSegment { size_t size; @@ -394,8 +392,6 @@ findInOrderSuccessor(struct memSegment * tree) return node; } -struct memSegment * deleteOneChild(struct memSegment **, struct memSegment *); - struct memSegment * deleteElement(struct memSegment ** tree, struct memSegment * element) { @@ -619,8 +615,6 @@ deleteElement(struct memSegment ** tree, struct memSegment * element) break; } - //deleteOneChild(tree, node); - return del_node; }