Browse Source
use now my own tree implementation as base for my hashes....sadly this thing is leaking memory again...on the other hand I workarounded the problem of a sometimes occuring infinite loop within connect.
release0.1.5
use now my own tree implementation as base for my hashes....sadly this thing is leaking memory again...on the other hand I workarounded the problem of a sometimes occuring infinite loop within connect.
release0.1.5
25 changed files with 1144 additions and 102 deletions
-
1configure.ac
-
3include/hash/hash.h
-
138include/tree.h
-
5src/Makefile.am
-
7src/asset/asset.c
-
19src/asset/pool.c
-
21src/hash/add.c
-
58src/hash/delete.c
-
8src/hash/each.c
-
19src/hash/get.c
-
9src/hash/hash.c
-
4src/rbtree.c
-
144src/rbtree2.c
-
6src/server/run.c
-
9src/tree/Makefile.am
-
248src/tree/delete.c
-
84src/tree/destroy.c
-
49src/tree/find.c
-
37src/tree/inOrderSuccessor.c
-
152src/tree/insert.c
-
51src/tree/rotateLeft.c
-
51src/tree/rotateRight.c
-
54src/tree/tree.c
-
59src/tree/walk.c
-
8src/utils/memory.c
@ -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 <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#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: |
||||
@ -0,0 +1,144 @@ |
|||||
|
#include <stdio.h> |
||||
|
|
||||
|
#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<depth; i++) printf("-"); |
||||
|
puts(""); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/** |
||||
|
* ======================================================================= |
||||
|
*/ |
||||
|
int |
||||
|
main(int argc, char * argv[]) |
||||
|
{ |
||||
|
Tree root = NULL; |
||||
|
int * found = NULL; |
||||
|
int values[] = {40, 50, 60, 70, 80, 45, 75, 85}; |
||||
|
int new50 = 50; |
||||
|
int new70 = 70; |
||||
|
int new80 = 80; |
||||
|
int search10 = 10; |
||||
|
int search64 = 64; |
||||
|
|
||||
|
treeInsert(&root, (void *)&(values[0]), insertCompare); |
||||
|
treeInsert(&root, (void *)&(values[1]), insertCompare); |
||||
|
treeInsert(&root, (void *)&(values[2]), insertCompare); |
||||
|
treeInsert(&root, (void *)&(values[3]), insertCompare); |
||||
|
treeInsert(&root, (void *)&(values[4]), insertCompare); |
||||
|
treeInsert(&root, (void *)&(values[5]), insertCompare); |
||||
|
treeInsert(&root, (void *)&(values[6]), insertCompare); |
||||
|
treeInsert(&root, (void *)&(values[7]), insertCompare); |
||||
|
puts("traverse"); |
||||
|
treeWalk(root, printNode); |
||||
|
puts(""); |
||||
|
|
||||
|
found = treeInsert(&root, (void *)&new70, insertCompare); |
||||
|
printf("insert %p(%d) got %p(%d)\n", &new70, new70, found, *found); |
||||
|
puts("traverse"); |
||||
|
treeWalk(root, printNode); |
||||
|
puts(""); |
||||
|
|
||||
|
found = treeFind(root, &search10, insertCompare); |
||||
|
if (NULL == found) { |
||||
|
printf("can't find segmenet of minimum size: %d\n", 10); |
||||
|
} else { |
||||
|
printf("found %d\n", *found); |
||||
|
} |
||||
|
puts(""); |
||||
|
|
||||
|
found = treeFind(root, &search64, insertCompare); |
||||
|
if (NULL == found) { |
||||
|
printf("can't find segmenet of minimum size: %d\n", 64); |
||||
|
} else { |
||||
|
printf("found %d\n", *found); |
||||
|
} |
||||
|
puts(""); |
||||
|
|
||||
|
found = treeFind(root, &new70, insertCompare); |
||||
|
if (NULL == found) { |
||||
|
printf("can't find segmenet of minimum size: %d\n", 70); |
||||
|
} else { |
||||
|
printf("found %d\n", *found); |
||||
|
} |
||||
|
puts(""); |
||||
|
|
||||
|
found = treeDelete(&root, (void *)&new70, insertCompare); |
||||
|
printf("delete %p(%d) got %p(%d)\n", &new70, new70, found, *found); |
||||
|
puts("traverse"); |
||||
|
treeWalk(root, printNode); |
||||
|
puts(""); |
||||
|
|
||||
|
found = treeInsert(&root, (void *)&new80, insertCompare); |
||||
|
printf("insert %p(%d) got %p(%d)\n", &new80, new80, found, *found); |
||||
|
found = treeInsert(&root, (void *)&new50, insertCompare); |
||||
|
printf("insert %p(%d) got %p(%d)\n", &new50, new50, found, *found); |
||||
|
found = treeInsert(&root, (void *)&new80, insertCompare); |
||||
|
printf("insert %p(%d) got %p(%d)\n", &new80, new80, found, *found); |
||||
|
|
||||
|
puts("traverse"); |
||||
|
treeWalk(root, printNode); |
||||
|
puts(""); |
||||
|
|
||||
|
found = treeDelete(&root, (void *)&new80, insertCompare); |
||||
|
printf("delete %p(%d) got %p(%d)\n", &new80, new80, found, *found); |
||||
|
puts("traverse"); |
||||
|
treeWalk(root, printNode); |
||||
|
puts(""); |
||||
|
|
||||
|
found = treeDelete(&root, (void *)&new50, insertCompare); |
||||
|
printf("delete %p(%d) got %p(%d)\n", &new50, new50, found, *found); |
||||
|
puts("traverse"); |
||||
|
treeWalk(root, printNode); |
||||
|
puts(""); |
||||
|
|
||||
|
found = treeDelete(&root, (void *)&new70, insertCompare); |
||||
|
printf("delete %p(%d) got %p(%d)\n", &new70, new70, found, found?*found:-1); |
||||
|
puts("traverse"); |
||||
|
treeWalk(root, printNode); |
||||
|
puts(""); |
||||
|
|
||||
|
found = treeDelete(&root, (void *)&(values[2]), insertCompare); |
||||
|
printf("delete %p(%d) got %p(%d)\n", |
||||
|
&(values[2]), |
||||
|
values[2], |
||||
|
found, |
||||
|
found?*found:-1); |
||||
|
puts("traverse"); |
||||
|
treeWalk(root, printNode); |
||||
|
puts(""); |
||||
|
|
||||
|
// |
||||
|
// post(root, cleanup); |
||||
|
|
||||
|
return 0; |
||||
|
} |
||||
|
|
||||
|
// vim: set et ts=4 sw=4: |
||||
@ -0,0 +1,9 @@ |
|||||
|
ACLOCAL_AMFLAGS = -I m4 |
||||
|
|
||||
|
TREE = tree.c find.c insert.c inOrderSuccessor.c delete.c walk.c \
|
||||
|
rotateLeft.c rotateRight.c destroy.c |
||||
|
|
||||
|
noinst_LIBRARIES = libtree.a |
||||
|
|
||||
|
libtree_a_SOURCES = $(TREE) |
||||
|
libtree_a_CFLAGS = $(CFLAGS) -Wall -I ../../include/ |
||||
@ -0,0 +1,248 @@ |
|||||
|
/** |
||||
|
* \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 <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#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: |
||||
@ -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 <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#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: |
||||
@ -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 <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#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: |
||||
@ -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 <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#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: |
||||
@ -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 <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#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: |
||||
@ -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 <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#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: |
||||
@ -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 <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#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: |
||||
@ -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 <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#define _GNU_SOURCE |
||||
|
|
||||
|
#include <stdarg.h> |
||||
|
|
||||
|
#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: |
||||
@ -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 <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#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: |
||||
Write
Preview
Loading…
Cancel
Save
Reference in new issue