tree

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

commit a97217b6f99c2488f6e8863f190d63e45a93a85e
parent 54bee5992078ea52f4a2b2b3da2b5aad8ccf5284
Author: Remy Noulin <loader2x@gmail.com>
Date:   Sun, 30 Dec 2018 12:05:07 +0100

implement wavlTree (malloc nodes)

.gitignore  |  11 ++
main.c      |  56 ++++++
package.yml |  31 ++++
tree.h      |   3 +
wavl.h      | 603 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
wavlTest.c  | 441 ++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 1145 insertions(+)

Diffstat:
M.gitignore | 11+++++++++++
Amain.c | 56++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Apackage.yml | 31+++++++++++++++++++++++++++++++
Atree.h | 3+++
Awavl.h | 603+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AwavlTest.c | 441+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 1145 insertions(+), 0 deletions(-)

diff --git a/.gitignore b/.gitignore @@ -1,3 +1,14 @@ +# Vim +*.sw* + +# Debug +.gdb_history + +# Coverage +*.gcov +*.gcda +*.gcno + # Prerequisites *.d diff --git a/main.c b/main.c @@ -0,0 +1,56 @@ +#! /usr/bin/env sheepy +/* or direct path to sheepy: #! /usr/local/bin/sheepy */ + +/* Libsheepy documentation: http://spartatek.se/libsheepy/ */ +#include "libsheepyObject.h" +#include "wavl.h" + +int argc; char **argv; + +/* enable/disable logging */ +/* #undef pLog */ +/* #define pLog(...) */ + +wavlDef(/* scope */, w /* wt wavl tree type and wNodet node type */, W /* function suffix: initW...*/, u32 /* keyType*/, u32 /* valueType */); + +wt tree; + +void freeKV(u32* /* keyType */ key, u32* /* valueType*/ value) { +} + +#define FREEFUNC freeKV +#define CMPFUNC CMP + +wavlFunctions(/* scope */, w /* wt wavl tree type*/, W /* function suffix: initW...*/, u32 /* keyType*/, u32 /* valueType */, -1 /* null key */, -1 /* null value */); + +int main(int ARGC, char** ARGV) { + + argc = ARGC; argv = ARGV; + + initLibsheepy(ARGV[0]); + setLogMode(LOG_FUNC); + + initW(&tree); + + addW(&tree, 0, 0); + addW(&tree, 1, 1); + addW(&tree, 10, 10); + addW(&tree, 5, 5); + + var n = getW(&tree, 10); + logVarG(n); + + // tree.inOrderTraversal(tree.root); + iterStartW(&tree, getFirstEntryW(&tree)); + wNodet *node; + while(node = nextW(&tree)) { + logVarG(node->key); + logVarG(node->value); + } + + delW(&tree, 10); + + freeW(&tree); + +} +// vim: set expandtab ts=2 sw=2: diff --git a/package.yml b/package.yml @@ -0,0 +1,31 @@ +--- + name: tree + version: 0.0.1 + description: "tree data stuctures: WAVL (weak AVL) tree" + bin: ./tree.h + #cflags: -DA -ggdb -std=gnu11 -fPIC -pipe + #lflags: -lpcre + repository: + type: git + url: git+https://github.com/RemyNoulin/tree.git + keywords: + - data stucture + author: Remy + license: MIT + bugs: + url: https://github.com/USER/RemyNoulin/issues + homepage: https://github.com/RemyNoulin/tree#readme + #compileHelp: # text displayed when there is a compilation error + #dependencies: + # md4c: + # Test configuration: + #testBin: ./testTree.c + #testCflags: -ggdb -std=gnu11 -fPIC -pipe -fprofile-arcs -ftest-coverage -Wall -Wextra + #testLflags: -lcheck_pic -lrt -lm -lsubunit -fprofile-arcs -ftest-coverage -rdynamic + # Memcheck configuration: + #memcheckBin: ./memcheckTree.c + #memcheckCmd: valgrind --leak-check=full --show-leak-kinds=all + #memcheckCflags: -ggdb -std=gnu11 -fPIC -pipe + #memcheckLflags: -rdynamic + #documentationCmd: # command for generating the documentation with spm doc + private: false # true for private package diff --git a/tree.h b/tree.h @@ -0,0 +1,3 @@ +#pragma once + +#include "wavl.h" diff --git a/wavl.h b/wavl.h @@ -0,0 +1,603 @@ +#pragma once + +#include "libsheepyObject.h" + +/** + * + * TODO add leftMost, rightMost pointer in tree + * + * void printTree(typeName##Nodet *X) { + * if (!X) return; + * + * printf("value %d, rank %d", X->value, X->rank); + * if (X->left) { + * printf(" left key %d", X->left->key); + * } + * else + * printf(" no left"); + * if (X->right) { + * printf(" right key %d", X->right->key); + * } + * else + * printf(" no right"); + * printf("\n"); + * + * inOrderTraversal(X->left); + * inOrderTraversal(X->right); + * } + * + * void inOrderTraversal(typeName##Nodet *X) { + * if (!X) return; + * + * inOrderTraversal(X->left); + * printf("value %d, rank %d\n", X->value, X->rank); + * inOrderTraversal(X->right); + * } + */ + +// init +// height +// empty FREEFUNC +// isEmpty +// free +// add CMPFUNC +// addOrFind +// find +// get +// g##suffixetKey +// del +// addOrFindNode +// getNode +// delNode + +// iterator + +#define wavlDef(scope, typeName, suffix, keyType, valueType)\ + wavlNodeT(typeName##Nodet, keyType, valueType);\ + wavlTreeT(typeName##t, typeName##Nodet, keyType, valueType);\ + scope void init##suffix(typeName##t *tree);\ + scope int height##suffix(typeName##t *tree);\ + scope void empty##suffix(typeName##t *tree);\ + scope bool isEmpty##suffix(typeName##t *tree);\ + scope void free##suffix(typeName##t *tree);\ + scope bool add##suffix(typeName##t *tree, keyType key, valueType value);\ + scope valueType* addOrFind##suffix(typeName##t *tree, keyType key, bool *isnew);\ + scope valueType* find##suffix(typeName##t *tree, keyType key);\ + scope valueType get##suffix(typeName##t *tree, keyType key);\ + scope keyType getKey##suffix(typeName##t *tree, keyType key);\ + 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 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) + +#define wavlFunctions(scope, typeName, suffix, keyType, valueType, nullKeyV, nullValueV)\ + scope void init##suffix(typeName##t *tree) {\ + wavlInit(tree, nullKeyV, nullValueV);\ + }\ + internal typeName##Nodet* newNode##suffix(keyType k, typeName##Nodet *parent) {\ + ret wavlNewNode(k, parent);\ + }\ + internal int nodeHeight##suffix(typeName##Nodet *node) {\ + if (!node) {\ + ret 0;\ + }\ + ret (1 + maxV(nodeHeight##suffix(node->left), nodeHeight##suffix(node->right)));\ + }\ + scope int height##suffix(typeName##t *tree) {\ + ret nodeHeight##suffix(tree->root) - 1;\ + }\ + internal void freeNodes##suffix(typeName##Nodet *node) {\ + if (!node) ret;\ + freeNodes##suffix(node->left);\ + freeNodes##suffix(node->right);\ + FREEFUNC(&node->key, &node->value);\ + free(node);\ + }\ + scope void empty##suffix(typeName##t *tree) {\ + freeNodes##suffix(tree->root);\ + tree->modCount++;\ + tree->count = 0;\ + tree->root = NULL;\ + tree->rotations = 0;\ + }\ + scope bool isEmpty##suffix(typeName##t *tree) {\ + ret tree->root == NULL;\ + }\ + scope void free##suffix(typeName##t *tree) {\ + empty##suffix(tree);\ + /* TODO free internal buffers */\ + }\ + /** insert new (key,value), fail when the key already exists */\ + scope bool add##suffix(typeName##t *tree, keyType key, valueType value) {\ + bool isnew;\ + var node = addOrFindNode##suffix(tree, key, &isnew);\ + if (isnew) {\ + node->value = value;\ + }\ + ret isnew;\ + }\ + scope valueType* addOrFind##suffix(typeName##t *tree, keyType key, bool *isnew) {\ + var node = addOrFindNode##suffix(tree, key, isnew);\ + return &node->value;\ + }\ + scope valueType* find##suffix(typeName##t *tree, keyType key) {\ + var node = getNode##suffix(tree, key);\ + ret !node ? NULL : &node->value;\ + }\ + scope valueType get##suffix(typeName##t *tree, keyType key) {\ + var node = getNode##suffix(tree, key);\ + ret !node ? tree->nullValue : node->value;\ + }\ + scope keyType getKey##suffix(typeName##t *tree, keyType key) {\ + var node = getNode##suffix(tree, key);\ + ret !node ? tree->nullKey : node->key;\ + }\ + scope void del##suffix(typeName##t *tree, keyType key) {\ + var node = getNode##suffix(tree, key);\ + if (!node) ret;\ + delNode##suffix(tree, node);\ + }\ + internal bool needToRotateLeft##suffix(typeName##Nodet *P) {\ + if (!P->left) {\ + /* rank of sibling is -1 */\ + if (P->rank == 1)\ + ret true;\ + ret false;\ + }\ + elif (P->rank >= P->left->rank + 2)\ + ret true;\ + ret false;\ + }\ + internal bool needToRotateRight##suffix(typeName##Nodet *P) {\ + if (!P->right) {\ + /* rank of sibling is -1 */\ + if (P->rank == 1)\ + ret true;\ + ret false;\ + }\ + elif (P->rank >= P->right->rank + 2)\ + ret true;\ + ret false;\ + }\ + internal void rotateLeft##suffix(typeName##t *tree, typeName##Nodet *P) {\ + typeName##Nodet *node = P->right;\ + P->right = node->left;\ + if (node->left)\ + node->left->parent = P;\ + node->parent = P->parent;\ + if (!P->parent)\ + tree->root = node;\ + elif (P->parent->left == P)\ + P->parent->left = node;\ + else\ + P->parent->right = node;\ + node->left = P;\ + P->parent = node;\ + tree->rotations++;\ + }\ + internal void rotateRight##suffix(typeName##t *tree, typeName##Nodet *P) {\ + typeName##Nodet *node = P->left;\ + P->left = node->right;\ + if (node->right)\ + node->right->parent = P;\ + node->parent = P->parent;\ + if (!P->parent)\ + tree->root = node;\ + elif (P->parent->right == P)\ + P->parent->right = node;\ + else\ + P->parent->left = node;\ + node->right = P;\ + P->parent = node;\ + tree->rotations++;\ + }\ + /** + * - If the path of incremented ranks reaches the root of the tree stoP-> + * - If the path of incremented ranks reaches a node whose parent's rank previously differed by two and after incrementing now differ by one stoP-> + * - If the procedure increases the rank of a node x, so that it becomes equal to the rank of the parent y of x, + * but the other child of y has a rank that is smaller by two (so that the rank of y cannot be increased) + * then again the rebalancing procedure stops after performing rotations necessary. + * + * In other words: + * After insertion rank difference is 1,2 or 3 - + * check these three cases stopping after any rotations, reaching the root or when rank difference was 2 before the insertion. + */\ + internal void balanceAfterInsert##suffix(typeName##t *tree, typeName##Nodet *node) {\ + for(typeName##Nodet *P = node->parent ; P && (node->rank+1 != P->rank) ; node->rank++) {\ + if (P->left == node) {\ + /* new node was added on the left */\ + if (needToRotateRight##suffix(P)) {\ + if (!node->left || node->rank >= node->left->rank+2) {\ + node->rank--;\ + node->right->rank++;\ + rotateLeft##suffix(tree, node);\ + }\ + P->rank--;\ + rotateRight##suffix(tree, P);\ + break;\ + }\ + }\ + else {\ + if (needToRotateLeft##suffix(P)) {\ + if (!node->right || node->rank >= node->right->rank+2) {\ + node->rank--;\ + node->left->rank++;\ + rotateRight##suffix(tree, node);\ + }\ + P->rank--;\ + rotateLeft##suffix(tree, P);\ + break;\ + }\ + }\ + node = P;\ + P = node->parent;\ + }\ + }\ + scope typeName##Nodet* addOrFindNode##suffix(typeName##t *tree, keyType key, bool *isnew) {\ + var O = tree->root;\ + if (!O) {\ + /* tree is empty, new node is root */\ + *isnew = true;\ + tree->root = newNode##suffix(key, NULL);\ + tree->count = 1;\ + tree->modCount++;\ + ret tree->root;\ + }\ + \ + /* Find the proper position for this new node */\ + int cmp;\ + typeName##Nodet *P;\ + do {\ + P = O;\ + cmp = CMPFUNC(key, O->key);\ + /* Decide which side of the current parent-under-consideration the + * new node to be inserted belongs on. */\ + if (cmp < 0)\ + O = O->left;\ + elif (cmp > 0)\ + O = O->right;\ + else {\ + /* Looks like we collided with an object in the tree which has + * the same key as the key in parameters + * return previous value */\ + *isnew = false;\ + ret O;\ + }\ + /* If we would have run out of valid pointers in the direction we + * should be searching, then we are done */\ + } while(O);\ + \ + *isnew = true;\ + var e = newNode##suffix(key, P);\ + /*logI("New %p", e);*/\ + if (cmp < 0) {\ + P->left = e;\ + }\ + else {\ + P->right = e;\ + }\ + \ + if (!P->rank) {\ + P->rank++;\ + balanceAfterInsert##suffix(tree, P);\ + }\ + \ + tree->count++;\ + tree->modCount++;\ + \ + ret e;\ + }\ + scope typeName##Nodet* getNode##suffix(typeName##t *tree, keyType key) {\ + var p = tree->root;\ + while (p) {\ + int cmp = CMPFUNC(key, p->key);\ + if (cmp < 0)\ + p = p->left;\ + elif (cmp > 0)\ + p = p->right;\ + else {\ + /*logI("Entry: %p", P);*/\ + ret p;\ + }\ + }\ + ret NULL;\ + }\ + internal int8_t rank##suffix(typeName##Nodet *node) {\ + ret !node ? -1 : node->rank;\ + }\ + internal bool nodeIsTwoTwo##suffix(typeName##Nodet *node) {\ + if (!node || !node->rank)\ + ret false;\ + if (node->rank == 1) {\ + if (!node->left && !node->right)\ + ret true;\ + else\ + ret false;\ + }\ + else\ + ret (node->left->rank == node->right->rank && (node->left->rank + 2 == node->rank));\ + }\ + internal void balanceAfterDeleteWAVL##suffix(typeName##t *tree, typeName##Nodet *parent, typeName##Nodet *sibling, int8_t nodeRank) {\ + typeName##Nodet *node;\ + int deltaRank = parent->rank - nodeRank;\ + while (deltaRank == 3 || parent->rank == 1 && nodeIsTwoTwo##suffix(parent)) {\ + int deltaRankSibling = (!sibling) ? parent->rank + 1 : parent->rank - sibling->rank;\ + if (deltaRankSibling == 2) {\ + parent->rank--; /* demote and continue loop */\ + } \ + else {\ + int deltaRankSiblingL = sibling->rank - rank##suffix(sibling->left);\ + int deltaRankSiblingR = sibling->rank - rank##suffix(sibling->right);\ + \ + if (deltaRankSiblingL == 2 && deltaRankSiblingR == 2) {\ + /* "double demote" in the orig. paper since both parent & sibling demote */\ + parent->rank--;\ + sibling->rank--;\ + }\ + elif (parent->right == sibling) {\ + /* delete was on the left */\ + if (deltaRankSiblingR == 1) {\ + /* single rotation */\ + sibling->rank++;\ + parent->rank--;\ + if (!sibling->left)\ + parent->rank--; /* demote parent again */\ + rotateLeft##suffix(tree, parent);\ + }\ + else {\ + /* double rotation */\ + parent->rank -= 2;\ + sibling->rank--;\ + sibling->left->rank += 2;\ + rotateRight##suffix(tree, sibling);\ + rotateLeft##suffix(tree, parent);\ + }\ + break;\ + }\ + else {\ + /* delete was on the right */\ + if (deltaRankSiblingL == 1) {\ + /* single rotation */\ + sibling->rank++;\ + parent->rank--;\ + if (!sibling->right)\ + parent->rank--; /* demote parent again */\ + rotateRight##suffix(tree, parent);\ + }\ + else {\ + /* double rotation */\ + parent->rank -= 2;\ + sibling->rank--;\ + sibling->right->rank += 2;\ + rotateLeft##suffix(tree, sibling);\ + rotateRight##suffix(tree, parent);\ + }\ + break;\ + }\ + }\ + \ + if (!parent->parent)\ + ret;\ + node = parent;\ + parent = parent->parent;\ + sibling = (parent->left == node) ? parent->right : parent->left;\ + deltaRank = parent->rank - node->rank;\ + }\ + }\ + scope typeName##Nodet *getFirstEntry##suffix(typeName##t *tree) {\ + typeName##Nodet *P = tree->root;\ + if (P) {\ + while (P->left)\ + P = P->left;\ + }\ + ret P;\ + }\ + scope typeName##Nodet *getLastEntry##suffix(typeName##t *tree) {\ + typeName##Nodet *P = tree->root;\ + if (P) {\ + while (P->right)\ + P = P->right;\ + }\ + ret P;\ + }\ + internal typeName##Nodet *successor##suffix(typeName##Nodet *X) {\ + if (!X)\ + ret NULL;\ + elif (X->right != NULL) {\ + typeName##Nodet *P = X->right;\ + while (P->left)\ + P = P->left;\ + ret P;\ + }\ + else {\ + typeName##Nodet *P = X->parent;\ + typeName##Nodet *ch = X;\ + while (P && ch == P->right) {\ + ch = P;\ + P = P->parent;\ + }\ + ret P;\ + }\ + }\ + internal typeName##Nodet *predecessor##suffix(typeName##Nodet *X) {\ + if (!X)\ + ret NULL;\ + elif (X->left) {\ + typeName##Nodet *P = X->left;\ + while (P->right)\ + P = P->right;\ + ret P;\ + }\ + else {\ + typeName##Nodet *P = X->parent;\ + typeName##Nodet *ch = X;\ + while (P && ch == P->left) {\ + ch = P;\ + P = P->parent;\ + }\ + ret P;\ + }\ + }\ + scope void delNode##suffix(typeName##t *tree, typeName##Nodet *node) {\ + tree->modCount++;\ + tree->count--;\ + \ + /* If strictly internal, copy successor's element to p and then make node + * point to successor. */\ + if (node->left && node->right) {\ + typeName##Nodet *X = predecessor##suffix(node);\ + node->key = X->key;\ + node->value = X->value;\ + node = X;\ + } /* p has 2 children */\ + \ + typeName##Nodet *replacement = (node->left ? node->left : node->right);\ + if (replacement) {\ + /* Link replacement to parent */\ + replacement->parent = node->parent;\ + typeName##Nodet *sibling = NULL;\ + if (!node->parent) {\ + tree->root = replacement;\ + FREEFUNC(&node->key, &node->value);\ + free(node);\ + ret;\ + }\ + elif (node == node->parent->left) {\ + node->parent->left = replacement;\ + sibling = node->parent->right;\ + }\ + else {\ + node->parent->right = replacement;\ + sibling = node->parent->left;\ + }\ + \ + /* Null out links so they are OK to use by fixAfterDeletion. */\ + node->left = node->right = node->parent = NULL;\ + FREEFUNC(&node->key, &node->value);\ + free(node);\ + balanceAfterDeleteWAVL##suffix(tree, replacement->parent, sibling, replacement->rank);\ + }\ + elif (!node->parent) {\ + /* return if we are the only node. */\ + FREEFUNC(&node->key, &node->value);\ + free(node);\ + tree->root = NULL;\ + ret;\ + }\ + else {\ + /* No children. Use self as phantom replacement and unlink. */\ + typeName##Nodet *fixPoint = node->parent;\ + typeName##Nodet *sibling = NULL;\ + \ + if (node == node->parent->left) {\ + node->parent->left = NULL;\ + sibling = fixPoint->right;\ + }\ + elif (node == node->parent->right) {\ + node->parent->right = NULL;\ + sibling = fixPoint->left;\ + }\ + node->parent = NULL;\ + int8_t rk = --node->rank;\ + FREEFUNC(&node->key, &node->value);\ + free(node);\ + balanceAfterDeleteWAVL##suffix(tree, fixPoint, sibling, rk);\ + }\ + }\ + scope void iterStart##suffix(typeName##t *tree, typeName##Nodet *first) {\ + tree->expectedModCount = tree->modCount;\ + tree->lastReturned = NULL;\ + tree->next = first;\ + }\ + scope bool hasNext##suffix(typeName##t *tree) {\ + ret tree->next != NULL;\ + }\ + scope typeName##Nodet *next##suffix(typeName##t *tree) {\ + typeName##Nodet *e = tree->next;\ + if (!e) ret NULL;\ + if (tree->modCount != tree->expectedModCount) ret NULL;\ + tree->next = successor##suffix(e);\ + tree->lastReturned = e;\ + ret e;\ + }\ + scope typeName##Nodet *prev##suffix(typeName##t *tree) {\ + typeName##Nodet *e = tree->next;\ + if (!e) ret NULL;\ + if (tree->modCount != tree->expectedModCount) ret NULL;\ + tree->next = predecessor##suffix(e);\ + tree->lastReturned = e;\ + ret e;\ + }\ + scope bool removeCurrent##suffix(typeName##t *tree) {\ + if (!tree->lastReturned) ret false;\ + if (tree->modCount != tree->expectedModCount) ret false;\ + /* // deleted entries are replaced by their successors */\ + /* if (tree->lastReturned.left && tree->lastReturned.right) */\ + /* tree->next = tree->lastReturned; */\ + delNode##suffix(tree, tree->lastReturned);\ + tree->expectedModCount = tree->modCount;\ + tree->lastReturned = NULL;\ + ret true;\ + } + + +#define wavlNodeT(typeName, keyType, valueType)\ + typ struct typeName typeName;\ + struct typeName {\ + keyType key;\ + valueType value;\ + typeName *left;\ + typeName *right;\ + typeName *parent;\ + i8 rank;\ + } + +#define wavlTreeT(typeName, nodeType, keyType, valueType)\ + typ struct {\ + size_t count; /* number of entries in the tree */\ + size_t modCount; /* number of structural modifications to the tree */\ + size_t rotations;\ + nodeType *root;\ + keyType nullKey;\ + valueType nullValue;\ + /* private iterator */\ + size_t expectedModCount;\ + nodeType *next;\ + nodeType *lastReturned;\ + /* end private iterator */\ + } typeName + +#define wavlInit(t, nullKeyV, nullValueV) do {\ + if (!t) break;\ + t->count = 0;\ + t->modCount = 0;\ + t->rotations = 0;\ + t->root = NULL;\ + t->nullKey = nullKeyV;\ + t->nullValue = nullValueV;\ + t->expectedModCount = -1;\ + t->next = NULL;\ + t->lastReturned = NULL;\ + } while(0) + +#define wavlNewNode(k, parent) ({\ + typeof(parent) r = malloc(sizeof(*parent));\ + if (r) {\ + r->key = k;\ + r->left = NULL;\ + r->right = NULL;\ + r->parent = parent;\ + r->rank = 0;\ + }\ + r;\ + }) + + +// vim: set expandtab ts=2 sw=2: diff --git a/wavlTest.c b/wavlTest.c @@ -0,0 +1,441 @@ +#! /usr/bin/env sheepy +/* or direct path to sheepy: #! /usr/local/bin/sheepy */ + +/* Libsheepy documentation: http://spartatek.se/libsheepy/ */ +#include "libsheepyObject.h" +#include "wavl.h" + +int argc; char **argv; + +/* enable/disable logging */ +/* #undef pLog */ +/* #define pLog(...) */ + +wavlDef(/* scope */, w /* wt wavl tree type and wNodet node type */, W /* function suffix: initW...*/, u32 /* keyType*/, u32 /* valueType */); + +void freeKV(u32* /* keyType */ key, u32* /* valueType*/ value) { +} + +#define FREEFUNC freeKV +#define CMPFUNC CMP + +wavlFunctions(/* scope */, w /* wt wavl tree type*/, W /* function suffix: initW...*/, u32 /* keyType*/, u32 /* valueType */, -1 /* null key */, -1 /* null value */); + +/* declare tree */ +wt x; + +#define assertEquals(A,B) do{\ + var a = A;\ + var b = B;\ + if (a != b) {\ + AT;\ + logI(BLD RED"assert failed:"RST" %d != %d\n", a, b);\ + }\ + }while(0) + +#define assertNull(p) do{\ + if (p) {\ + AT;\ + logE(BLD RED"assert failed:"RST stringifyExpr(p) " not NULL\n");\ + }\ + }while(0) + +#define assertTrue(c) do{\ + if (!(c)) {\ + AT;\ + logE(BLD RED"assert failed: "RST stringifyExpr(c) " expected true\n");\ + }\ + }while(0) + +void testTreeHeight() { + emptyW(&x); + addW(&x,2, 2); + assertEquals(0, heightW(&x)); + addW(&x,3, 3); + assertEquals(1, heightW(&x)); + addW(&x,1, 1); + addW(&x,0, 0); + assertEquals(2, heightW(&x)); +} + +void testInsertDoNothing() { + emptyW(&x); + addW(&x,2, 2); + addW(&x,3, 3); + assertEquals(0, x.rotations); + assertEquals(2, (int)x.root->value); + assertEquals(1, x.root->rank); + + addW(&x,1, 1); + assertEquals(2, (int)x.root->value); + + assertEquals(1, x.root->rank); + assertEquals(0, x.rotations); +} + +void testInsert100() { + emptyW(&x); + for (int i=0; i<100; i++) + addW(&x,i, i); + assertEquals(100, x.count); +} + +void testInsertMany() { + emptyW(&x); + int a[] = {477, 1193, 2130,398,1393,946,422,1381,1767,830,570,1085,741,598,1658,1801,487,1921,1918,258,135,975,1870}; + for (int i=0; i < ARRAY_SIZE(a); i++) + addW(&x,a[i], a[i]); + assertEquals(1193, (int) x.root->value); + assertEquals(1767, (int) x.root->right->value); + assertEquals(1393, (int) x.root->right->left->value); + assertEquals(1921, (int) x.root->right->right->value); + assertEquals(1870, (int) x.root->right->right->left->value); + assertEquals(1801, (int) x.root->right->right->left->left->value); + assertEquals(2130, (int) x.root->right->right->right->value); +} + +void testInsertOneLeftRotation() { + emptyW(&x); + addW(&x,1, 1); + addW(&x,2, 2); + addW(&x,3, 3); + + assertEquals(1, x.root->rank); + assertEquals(2, (int) x.root->value); + assertEquals(0, x.root->right->rank); +} + +void testInsertTwoLeftRotations() { + emptyW(&x); + addW(&x,1, 1); + addW(&x,2, 2); + addW(&x,3, 3); + addW(&x,4, 4); + addW(&x,5, 5); + + assertEquals(2, x.root->rank); + assertEquals(2, (int) x.root->value); + assertEquals(2, x.rotations); + assertEquals(1, x.root->right->rank); + assertEquals(0, x.root->left->rank); +} + +void testInsertThreeLeftRotations() { + emptyW(&x); + addW(&x,1, 1); + addW(&x,2, 2); + addW(&x,3, 3); + addW(&x,4, 4); + addW(&x,5, 5); + addW(&x,6, 6); + + assertEquals(3, x.rotations); + assertEquals(4, (int) x.root->value); + assertEquals(2, x.root->rank); + assertTrue(x.root->right->rank == 1 && x.root->left->rank == 1); +} + + +void testInsertLeftRightRotation() { + emptyW(&x); + addW(&x,3, 3); + addW(&x,1, 1); + addW(&x,2, 2); + + assertEquals(2, x.rotations); + assertEquals(2, (int) x.root->value); + assertEquals(1, x.root->rank); +} + +void testInsertRightLeftRotation() { + emptyW(&x); + addW(&x,3, 3); + addW(&x,6, 6); + addW(&x,4, 4); + + assertEquals(2, x.rotations); + assertEquals(4, (int) x.root->value); + assertEquals(1, x.root->rank); +} + +void testInsertBuildFibonacciTree() { + emptyW(&x); + addW(&x,8, 8); + addW(&x,5, 5); + addW(&x,11, 11); + // 3,7,10,12 + addW(&x,3, 3); addW(&x,7, 7); addW(&x,10, 10); addW(&x,12, 12); + // 2,4,6,9 + addW(&x,2, 2); addW(&x,4, 4); addW(&x,6, 6); addW(&x,9, 9); + addW(&x,1, 1); + logI("Rotations: %d", x.rotations); + assertEquals(0, x.rotations); +} + +void testInsertFibAfterDelete() { + emptyW(&x); + addW(&x,8, 8); // root + addW(&x,5, 5); addW(&x,11, 11); + // 3,7,10,12 + addW(&x,3, 3); addW(&x,7, 7); addW(&x,10, 10); addW(&x,12, 12); + // 2,4,6,9 + addW(&x,2, 2); addW(&x,4, 4); addW(&x,6, 6); addW(&x,9, 9); + addW(&x,1, 1); + + delW(&x, 12); + //TODO +} + +void testInsert6() { + emptyW(&x); + for (int i=0; i<6; i++) + addW(&x,i, i); + assertEquals(3, x.rotations); + assertEquals(3, (int) x.root->value); + // TODO x.inOrderTraversal(x.root); +} + +void testInsertTwoRightRotations() { + emptyW(&x); + addW(&x,5, 5); + addW(&x,4, 4); + addW(&x,3, 3); + addW(&x,2, 4); + addW(&x,1, 1); + + assertEquals(2, x.rotations); + assertEquals(2, x.root->rank); + assertEquals(4, (int) x.root->value); + assertEquals(0, x.root->right->rank); + assertEquals(1, x.root->left->rank); +} + +void testDeleteNoRotationWAVL() { + emptyW(&x); + addW(&x,2, 2); + addW(&x,3, 3); + addW(&x,1, 1); + assertEquals(2, (int)x.root->value); + + delW(&x,3); + assertEquals(1, x.root->rank); + assertEquals(0, x.rotations); + + // remove root + delW(&x,2); + delW(&x,1); + assertEquals(0, x.count); +} + +void testDeleteOneRightRotationWAVL() { + emptyW(&x); + addW(&x,10, 10); + addW(&x,8, 8); addW(&x,12, 12); + addW(&x,6, 6); + + delW(&x,12); + /* + 8 + 6 10 + */ + assertEquals(1, x.rotations); + assertEquals(2, x.root->rank); // created 2,2 node, non-leaf + assertEquals(0, x.root->right->rank); + assertEquals(0, x.root->left->rank); + assertEquals(8, (int) x.root->value); +} + +void testDeleteOneRightRotationSiblingBalancedWAVL() { + emptyW(&x); + addW(&x,10, 10); + addW(&x,8, 8);addW(&x,12, 12); + addW(&x,6,6);addW(&x,9,9); + + assertEquals(0, x.rotations); + + delW(&x,12); + /* after + 8 + 6 10 + 9 + */ + assertEquals(2, x.root->rank); + assertEquals(6, (int) x.root->left->value); + assertEquals(1, x.root->right->rank); + assertEquals(0, x.root->right->left->rank); + assertEquals(0, x.root->left->rank); + assertEquals(8, (int) x.root->value); + assertEquals(1, x.rotations); +} + +void testDeleteOneLeftRightRotationWAVL() { + emptyW(&x); + addW(&x,10, 10); + addW(&x,8, 8); + addW(&x,12, 12); + addW(&x,9, 9); + + delW(&x,12); + /* + 9 + 8 10 + */ + + assertEquals(0, x.root->right->rank); + assertEquals(0, x.root->left->rank); + assertEquals(2, x.root->rank); // created 2,2 node + assertEquals(9, (int) x.root->value); + assertEquals(2, x.rotations); +} + +void testDelete5WAVL() { + emptyW(&x); + for (int i=0; i<6; i++) + addW(&x,i, i); + + // 3(2) + // 1(1) 4(1) + // 0(0) 2(0) - 5(0) + //x.inOrderTraversal(x.root); + + //logI("Rotations before remove: %d\n", x.rotations); + + for (int i=0; i<5; i++) { + logI("Root: k %d v %d Deleting: %d\n", x.root->key, x.root->value, i); + delW(&x,i); + } + + //logI("Rotations after remove: %d\n", x.rotations); + assertEquals(1, x.count); + assertEquals(0, x.root->rank); + + delW(&x,5); +} + +void testDeleteFibonacciTreeWAVL() { + emptyW(&x); + addW(&x,8, 8); // root + addW(&x,5, 5); addW(&x,11, 11); + // 3,7,10,12 + addW(&x,3, 3); addW(&x,7, 7); addW(&x,10, 10); addW(&x,12, 12); + // 2,4,6,9 + addW(&x,2, 2); addW(&x,4, 4); addW(&x,6, 6); addW(&x,9, 9); + addW(&x,1, 1); + + // 8(4) + // 5(3) 11(2) + // 3(2) 7(1) 10(1) 12(0) + // 2(1) 4(0) 6(0) - 9(0) - + // 1(0) - + + delW(&x, 12); + + logI("Rotations after remove 12: %d\n", x.rotations); + logI("ROOT: k %d v %d\n", x.root->key, x.root->value); + assertEquals(1, x.rotations); + assertEquals(8, (int) x.root->value); + assertEquals(0, x.root->right->right->rank); + assertEquals(0, x.root->right->left->rank); + assertEquals(2, x.root->right->rank); +} + +void testDeleteAlmostFibonacciTreeWAVL() { + emptyW(&x); + addW(&x,8, 8); // root + logVarG(getW(&x, 8)); + addW(&x,5, 5); addW(&x,12, 12); + // 3,7,10,12 + addW(&x,3, 3); addW(&x,7, 7); addW(&x,10, 10); addW(&x,13, 13); + // 2,4,6,9,11 + addW(&x,2, 2); addW(&x,4, 4); addW(&x,6, 6); addW(&x,9, 9); addW(&x,11,11); + addW(&x,1, 1); + + //x.inOrderTraversal(x.root); + //puts("\n"); + + delW(&x, 13); + + // 8(4) + // 5(3) 12(2) + // 3(2) 7(1) 10(1) - + // 2(1) 4(0) 6(0) - 9(0) 11(0) + // 1(0) - + //x.inOrderTraversal(x.root); + + /* int g[] = {8,5,12,3,7,10,13,2,4,6,9,11,1}; */ + /* range(i, ARRAY_SIZE(g)) { */ + /* var v = x.get(&x, g[i]); */ + /* if (v == -1) { */ + /* logI("key %d, "BLD YLW"not found"RST, g[i]); */ + /* } */ + /* else { */ + /* logI("key %d, value %d", g[i], x.get(&x, g[i])); */ + /* } */ + /* } */ + + logI("Rotations after remove 13: %d\n", x.rotations); + logI("ROOT: k %d v %d\n", x.root->key, x.root->value); + assertEquals(1, x.rotations); + assertEquals(8, (int) x.root->value); + assertEquals(1, x.root->right->right->rank); + assertEquals(0, x.root->right->left->rank); + assertEquals(2, x.root->right->rank); +} + +void testDeleteManyWAVL() { + emptyW(&x); + int a[] = {477,1193,2130,398,1393,946,422,1381,1767,830,570,1085,741,598,1658,1801,487,1921,1918,258,135,975,1870}; + for (int i=0; i < ARRAY_SIZE(a); i++) { + logI("put: %d,\n", a[i]); + addW(&x,a[i], a[i]); + } + puts("\n"); + + for (int i=ARRAY_SIZE(a)-1; i > 0; i--) { + logI("Deleting: %d value: %d\n", i, a[i]); + delW(&x, a[i]); + } + + // TODO x.inOrderTraversal(x.root); + + assertEquals(477, (int) x.root->value); + assertEquals(0, x.root->rank); + assertNull(x.root->left); + assertNull(x.root->right); +} + + +int main(int ARGC, char** ARGV) { + + argc = ARGC; argv = ARGV; + + initLibsheepy(ARGV[0]); + setLogMode(LOG_FUNC); + + initW(&x); + + testDelete5WAVL(); + testDeleteAlmostFibonacciTreeWAVL(); + testDeleteFibonacciTreeWAVL(); + testDeleteManyWAVL(); + testDeleteNoRotationWAVL(); + testDeleteOneLeftRightRotationWAVL(); + testDeleteOneRightRotationSiblingBalancedWAVL(); + testDeleteOneRightRotationWAVL(); + testInsert100(); + testInsert6(); + testInsertBuildFibonacciTree(); + testInsertDoNothing(); + testInsertFibAfterDelete(); + testInsertLeftRightRotation(); + testInsertMany(); + testInsertOneLeftRotation(); + testInsertRightLeftRotation(); + testInsertThreeLeftRotations(); + testInsertTwoLeftRotations(); + testInsertTwoRightRotations(); + testTreeHeight(); + + freeW(&x); +} +// vim: set expandtab ts=2 sw=2: