tree

tree data structures
git clone https://noulin.net/git/tree.git
Log | Files | Refs | README | LICENSE

commit ebb5aef76cc773b22f7e4198e467705d8532c3bd
parent 5f67edad2ec70060fffbc3b6a23f8b7e7abbae38
Author: Remy Noulin <loader2x@gmail.com>
Date:   Sun, 30 Dec 2018 16:32:00 +0100

improve documentation

README.md |  23 +++++++-
main.c    |   3 ++
wavl.h    | 179 +++++++++++++++++++++++++++++++++++++++++++++++++++++---------
3 files changed, 178 insertions(+), 27 deletions(-)

Diffstat:
MREADME.md | 23+++++++++++++++++++++--
Mmain.c | 3+++
Mwavl.h | 179++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
3 files changed, 178 insertions(+), 27 deletions(-)

diff --git a/README.md b/README.md @@ -1,2 +1,21 @@ -# tree -tree data structures +# Sheepy +This is a sheepy package for [sheepy](https://github.com/RemyNoulin/sheepy) and using [libsheepy](https://github.com/RemyNoulin/libsheepy) + +# Tree data structures + +All the trees in this package are type-safe. The types are selected when the tree is defined. + +## WAVL Tree + +`wavl.h` implements a weak AVL tree, see [wavlTree](https://github.com/RemyNoulin/wavlTree). + +The nodes are stored in a vector for better performance. + +# Usage + +Install with spm: `spm install tree` + +Include header file: +- `#include "shpPackages/tree/tree.h"` + +Usage examples are on the top of the headers and in `main.c`. diff --git a/main.c b/main.c @@ -23,6 +23,9 @@ void freeKV(u32* /* keyType */ key, u32* /* valueType*/ value) { wavlFunctions(/* scope */, w /* wt wavl tree type*/, W /* function suffix: initW...*/, u32 /* keyType*/, u32 /* valueType */, -1 /* null key */, -1 /* null value */); +#undef FREEFUNC +#undef CMPFUNC + int main(int ARGC, char** ARGV) { argc = ARGC; argv = ARGV; diff --git a/wavl.h b/wavl.h @@ -3,11 +3,93 @@ #include "libsheepyObject.h" /** + * \file * - * allocating node in dVector is slightly faster (in the order of 10% when the memory is not already map in the process) + * WAVL tree + * + * WAVL tree is type-safe binary search tree with characteristics from the AVL and red black trees. + * + * The iterator traverses the tree in sorted order (by key and CMPFUNC). + * + * The maximum number of nodes is 2^32 + * + * The tree nodes are stored in a dVector, since allocating node in dVector is slightly faster + * (in the order of 10% when the memory is not already map in the process) * than the version allocating nodes with malloc. (826ms vs 870ms for 10M elements) * - * TODO add leftMost, rightMost pointer in tree + * wavlDef defines 2 types for the tree: + * + * - 'typeName't is the type for the tree itself + * - 'typeName'Nodet is the node type in the tree + * + * The public functions follow the same pattern as the hashtable API in the hashtable sheepy package. + * + * init, empty, isEmpty, free, add, addOrFind, find, find, get, getKey, del, addOrFindNode, getNode, delNode behave + * like the ones for the hashtable. + * + * There are a few tree specific functions: + * + * height, iterStart, hasNext, next, prev, delCurrent + * + * The key and value in the node are accessed with: + * node->key + * node->value + * + * Before implementing the functions with wavlFunctions, define CMPFUNC and FREEFUNC + * + * - CMPFUNC compares 2 keys, prototype: int cmp(keyType k1, keyType k2); + * return -1 when k1 < k2, 0 when k1 = k2 and 1 when k1 > k2 + * - FREEFUNC frees key and value in a node, prototype: void freeKV(keyType *k, valueType *v); + * + * Redefine dVectorBits to change the size of the segments in dVector and tweak the memory usage and performance + * + * Example: + * // define WAVL tree: u32 key and u32 value + * wavlDef(, w, W, u32, u32); + * + * // declare tree + * wt tree; + * + * // free KV function + * void freeKV(u32* key, u32* value) { + * } + * + * // implement WAVL tree functions + * #define FREEFUNC freeKV + * #define CMPFUNC CMP + * + * wavlFunctions(, w, W, u32, u32, -1, -1); + * + * #undef FREEFUNC + * #undef CMPFUNC + * + * // initialize tree + * initW(&tree); + * + * // add key value pair + * addW(&tree, 0, 0); + * + * // get value for key + * var n = getW(&tree, 0); + * logVarG(n); + * + * // iterator from the lowest key to the highest key + * iterStartW(&tree, getFirstEntryW(&tree)); + * wNodet *node; + * while(node = nextW(&tree)) { + * logVarG(node->key); + * logVarG(node->value); + * } + * + * // delete a key value pair + * delW(&tree, 10); + * + * // free tree + * freeW(&tree); + * + * + * + * To traverse the tree and print all key value pairs, implement one of these functions: * * void printTree(typeName##Nodet *X) { * if (!X) return; @@ -36,25 +118,37 @@ * printf("value %d, rank %d\n", X->value, X->rank); * inOrderTraversal(X->right); * } + * + * TODO add leftMost, rightMost pointer in tree */ -// init -// height -// empty FREEFUNC -// isEmpty -// free -// add CMPFUNC -// addOrFind -// find -// get -// g##suffixetKey -// del -// addOrFindNode -// getNode -// delNode - -// iterator - +/** + * function declarations for tailored WAVL tree + * + * wavlDef defines: + * + * - 'typeName't is the type for the tree itself + * - 'typeName'Nodet is the node type in the tree + * - prototypes + * + * this macro is placed most of the time in a header file + * + * the function names are: + * function'suffix' + * + * the scope parameter is the function scope and can be 'empty' for global functions, 'static' for local functions, ... + * + * RETURN VALUES: + * height: tree height or -1 when empty + * isEmpty, add, hasNext, delCurrent: true success, false failure + * addOrFind, addOrFindNode: value or node pointer + * *isnew is set to true when the returned value pointer is in a new node + * find, getNode, next, prev: value or node pointer + * NULL failure + * get, getKey: value or key + * nullValueV or nullKeyV failure + * + */ #define wavlDef(scope, typeName, suffix, keyType, valueType)\ wavlNodeT(typeName##Nodet, keyType, valueType);\ wavlTreeT(typeName##t, typeName##Nodet, keyType, valueType);\ @@ -71,19 +165,32 @@ scope void del##suffix(typeName##t *tree, keyType key);\ scope typeName##Nodet* addOrFindNode##suffix(typeName##t *tree, keyType key, bool *isnew);\ scope typeName##Nodet* getNode##suffix(typeName##t *tree, keyType key);\ - scope typeName##Nodet *getFirstEntry##suffix(typeName##t *tree);\ - scope typeName##Nodet *getLastEntry##suffix(typeName##t *tree);\ + scope typeName##Nodet* getFirstEntry##suffix(typeName##t *tree);\ + scope typeName##Nodet* getLastEntry##suffix(typeName##t *tree);\ scope void delNode##suffix(typeName##t *tree, typeName##Nodet *node);\ scope void iterStart##suffix(typeName##t *tree, typeName##Nodet *first);\ scope bool hasNext##suffix(typeName##t *tree);\ - scope typeName##Nodet *next##suffix(typeName##t *tree);\ - scope typeName##Nodet *prev##suffix(typeName##t *tree);\ - scope bool removeCurrent##suffix(typeName##t *tree) + scope typeName##Nodet* next##suffix(typeName##t *tree);\ + scope typeName##Nodet* prev##suffix(typeName##t *tree);\ + scope bool delCurrent##suffix(typeName##t *tree) +/** + * function implementations + * + * this macros implements the tree functions + * + * this macro is placed most of the time in a source file + * + * the compare function and free function must be implemented before this macro + * CMPFUNC and FREEFUNC must be defined before this macro + * + */ #define wavlFunctions(scope, typeName, suffix, keyType, valueType, nullKeyV, nullValueV)\ + /* initialize tree */\ scope void init##suffix(typeName##t *tree) {\ wavlInit(tree, nullKeyV, nullValueV);\ }\ + /* allocate a new node */\ internal typeName##Nodet* newNode##suffix(typeName##t *tree, keyType k, typeName##Nodet *parent) {\ ret wavlNewNode(tree, k, parent);\ }\ @@ -93,6 +200,7 @@ }\ ret (1 + maxV(nodeHeight##suffix(node->left), nodeHeight##suffix(node->right)));\ }\ + /* tree height */\ scope int height##suffix(typeName##t *tree) {\ ret nodeHeight##suffix(tree->root) - 1;\ }\ @@ -103,6 +211,7 @@ FREEFUNC(&node->key, &node->value);\ dVectorAppend(&tree->freeNodeList, node->index);\ }\ + /* free all nodes in tree */\ scope void empty##suffix(typeName##t *tree) {\ freeNodes##suffix(tree, tree->root);\ tree->modCount++;\ @@ -110,9 +219,11 @@ tree->root = NULL;\ tree->rotations = 0;\ }\ + /* true when tree is empty */\ scope bool isEmpty##suffix(typeName##t *tree) {\ ret tree->root == NULL;\ }\ + /* free all nodes and tree internal buffer, after this the tree is not usable anymore */\ scope void free##suffix(typeName##t *tree) {\ empty##suffix(tree);\ dVectorFree(&tree->treeNodes);\ @@ -127,22 +238,27 @@ }\ ret isnew;\ }\ + /* insert or find key, when the key is not found a new node is created, return value pointer in node otherwise */\ scope valueType* addOrFind##suffix(typeName##t *tree, keyType key, bool *isnew) {\ var node = addOrFindNode##suffix(tree, key, isnew);\ return &node->value;\ }\ + /* find key, return value pointer or NULL upon failure */\ scope valueType* find##suffix(typeName##t *tree, keyType key) {\ var node = getNode##suffix(tree, key);\ ret !node ? NULL : &node->value;\ }\ + /* get value for key, return value or nullValue upon failure */\ scope valueType get##suffix(typeName##t *tree, keyType key) {\ var node = getNode##suffix(tree, key);\ ret !node ? tree->nullValue : node->value;\ }\ + /* get key in node, return key or nullKey upon failure */\ scope keyType getKey##suffix(typeName##t *tree, keyType key) {\ var node = getNode##suffix(tree, key);\ ret !node ? tree->nullKey : node->key;\ }\ + /* delete key and value using FREEFUNC */\ scope void del##suffix(typeName##t *tree, keyType key) {\ var node = getNode##suffix(tree, key);\ if (!node) ret;\ @@ -244,6 +360,7 @@ P = node->parent;\ }\ }\ + /* insert or find key, when the key is not found a new node is created, return node pointer */\ scope typeName##Nodet* addOrFindNode##suffix(typeName##t *tree, keyType key, bool *isnew) {\ var O = tree->root;\ if (!O) {\ @@ -298,6 +415,7 @@ \ ret e;\ }\ + /* get node pointer for key, return node pointer or NULL upon failure */\ scope typeName##Nodet* getNode##suffix(typeName##t *tree, keyType key) {\ var p = tree->root;\ while (p) {\ @@ -395,6 +513,7 @@ deltaRank = parent->rank - node->rank;\ }\ }\ + /* get node pointer for lowest key */\ scope typeName##Nodet *getFirstEntry##suffix(typeName##t *tree) {\ typeName##Nodet *P = tree->root;\ if (P) {\ @@ -403,6 +522,7 @@ }\ ret P;\ }\ + /* get node pointer for highest key */\ scope typeName##Nodet *getLastEntry##suffix(typeName##t *tree) {\ typeName##Nodet *P = tree->root;\ if (P) {\ @@ -449,6 +569,7 @@ ret P;\ }\ }\ + /* delete node */\ scope void delNode##suffix(typeName##t *tree, typeName##Nodet *node) {\ tree->modCount++;\ tree->count--;\ @@ -515,14 +636,17 @@ balanceAfterDeleteWAVL##suffix(tree, fixPoint, sibling, rk);\ }\ }\ + /* start iteration */\ scope void iterStart##suffix(typeName##t *tree, typeName##Nodet *first) {\ tree->expectedModCount = tree->modCount;\ tree->lastReturned = NULL;\ tree->next = first;\ }\ + /* has next node */\ scope bool hasNext##suffix(typeName##t *tree) {\ ret tree->next != NULL;\ }\ + /* get next node in iteration */\ scope typeName##Nodet *next##suffix(typeName##t *tree) {\ typeName##Nodet *e = tree->next;\ if (!e) ret NULL;\ @@ -531,6 +655,7 @@ tree->lastReturned = e;\ ret e;\ }\ + /* get previous node in iteration */\ scope typeName##Nodet *prev##suffix(typeName##t *tree) {\ typeName##Nodet *e = tree->next;\ if (!e) ret NULL;\ @@ -539,7 +664,8 @@ tree->lastReturned = e;\ ret e;\ }\ - scope bool removeCurrent##suffix(typeName##t *tree) {\ + /* delete current node in iteration, it is possible to continue the iteration after this */\ + scope bool delCurrent##suffix(typeName##t *tree) {\ if (!tree->lastReturned) ret false;\ if (tree->modCount != tree->expectedModCount) ret false;\ /* // deleted entries are replaced by their successors */\ @@ -552,6 +678,9 @@ } +// Internal macros +// use the function implementations instead + #define wavlNodeT(typeName, keyType, valueType)\ typ struct typeName typeName;\ struct typeName {\