diff options
author | Warren Dukes <warren.dukes@gmail.com> | 2006-07-30 18:43:13 +0000 |
---|---|---|
committer | Warren Dukes <warren.dukes@gmail.com> | 2006-07-30 18:43:13 +0000 |
commit | 71fe871908db4317e5afd4308a044909a1799c9e (patch) | |
tree | b6605a973562be001afa7b22372c7f5c9eefbded /src/tree.c | |
parent | 263a9d583a74a94fef652bb40f4035b9c0c1612e (diff) | |
download | mpd-71fe871908db4317e5afd4308a044909a1799c9e.tar.gz mpd-71fe871908db4317e5afd4308a044909a1799c9e.tar.xz mpd-71fe871908db4317e5afd4308a044909a1799c9e.zip |
tree updates:
*) when CHILDREN_PER_NODE is large, use binary search
*) add a iterator implementation
*) some code cleanup
git-svn-id: https://svn.musicpd.org/mpd/trunk@4492 09075e82-0dd4-0310-85a5-a0d7c8717e4f
Diffstat (limited to 'src/tree.c')
-rw-r--r-- | src/tree.c | 253 |
1 files changed, 203 insertions, 50 deletions
diff --git a/src/tree.c b/src/tree.c index 0696f4b13..58e8a221f 100644 --- a/src/tree.c +++ b/src/tree.c @@ -5,6 +5,36 @@ #include <string.h> #include <stdio.h> +#ifndef CHILDREN_PER_NODE +#define CHILDREN_PER_NODE 3 +#endif + +#define DATA_PER_NODE (CHILDREN_PER_NODE-1) + +#if CHILDREN_PER_NODE > 11 +#define USE_BINARY_SEARCH 1 +#endif + + +/************************* DATA STRUCTURES **********************************/ + +struct _TreeNode +{ + void * data[DATA_PER_NODE]; + struct _TreeNode * parent; + struct _TreeNode * children[CHILDREN_PER_NODE]; + int dataCount; +}; + +struct _Tree +{ + TreeCompareDataFunction compareData; + TreeFreeDataFunction freeData; + TreeNode * rootNode; +}; + +/************************* STATIC METHODS ***********************************/ + static TreeNode * _MakeNode() @@ -16,31 +46,63 @@ _MakeNode() static int +_FindPositionInNode(Tree * tree, TreeNode * node, void * data, int * pos) +{ +#ifdef USE_BINARY_SEARCH + int low = 0; + int high = node->dataCount; + int cmp = -1; + + while (high > low) + { + int cur = (high + low) >> 1; + cmp = tree->compareData(data, node->data[cur]); + if (cmp > 0) + { + low = cur+1; + } + else if (cmp < 0) + { + high = cur; + } + else + { + low = cur; + break; + } + } + + *pos = low; + return (cmp == 0); +#else + int i = 0; + int cmp = -1; + for (; + i < node->dataCount && + (cmp = tree->compareData(data, node->data[i])) > 0; + i++); + *pos = i; + return (cmp == 0); +#endif +} + +static +int _Find(TreeIterator * iter, void * data) { while (1) { - for (; iter->which < iter->node->dataCount; iter->which++) + if (_FindPositionInNode(iter->tree, + iter->node, + data, + &iter->which)) { - int comp = iter->tree-> - compareData(data,iter->node->data[iter->which]); - - if (comp == 0) - { - return 1; - } - else if (comp < 0) - { - break; - } + return 1; } - assert(iter->which < CHILDREN_PER_NODE); - if (iter->node->children[iter->which]) { iter->node = iter->node->children[iter->which]; - iter->which = 0; } else { @@ -49,16 +111,6 @@ _Find(TreeIterator * iter, void * data) } } -Tree * -MakeTree(TreeCompareDataFunction compareData, TreeFreeDataFunction freeData) -{ - Tree * ret = malloc(sizeof(Tree)); - ret->compareData = compareData; - ret->freeData = freeData; - ret->rootNode = _MakeNode(); - return ret; -} - static TreeNode * _SplitNode(TreeNode * node) @@ -67,21 +119,38 @@ _SplitNode(TreeNode * node) TreeNode * newNode = _MakeNode(); - unsigned i = DATA_PER_NODE/2; - unsigned j = 0; +#ifdef USE_MEM_FUNC + memcpy(&(newNode->data[0]), + &(node->data[DATA_PER_NODE/2]), + (DATA_PER_NODE-DATA_PER_NODE/2)*sizeof(void *)); + memset(&(node->data[DATA_PER_NODE/2]), + 0, + (DATA_PER_NODE-DATA_PER_NODE/2)*sizeof(void *)); + memcpy(&(newNode->children[1]), + &(node->children[DATA_PER_NODE/2+1]), + (DATA_PER_NODE-DATA_PER_NODE/2)*sizeof(TreeNode *)); + memset(&(node->children[DATA_PER_NODE/2+1]), + 0, + (DATA_PER_NODE-DATA_PER_NODE/2)*sizeof(TreeNode *)); +#endif + + int i = DATA_PER_NODE/2; + int j = 0; for (; i < DATA_PER_NODE; i++, j++) { +#ifndef USE_MEM_FUNC newNode->data[j] = node->data[i]; newNode->children[j+1] = node->children[i+1]; + node->data[i] = NULL; + node->children[i+1] = NULL; +#endif if (newNode->children[j+1]) { newNode->children[j+1]->parent = newNode; } - node->data[i] = NULL; - node->children[i+1] = NULL; } - newNode->dataCount = j; - node->dataCount -= j; + newNode->dataCount = (DATA_PER_NODE-DATA_PER_NODE/2); + node->dataCount -= (DATA_PER_NODE-DATA_PER_NODE/2); return newNode; } @@ -102,23 +171,29 @@ _InsertNodeAndData(Tree * tree, } int i = 0; - for (; - i < node->dataCount && - tree->compareData(data, node->data[i]) > 0; - i++); - + _FindPositionInNode(tree, node, data, &i); + +#ifdef USE_MEM_FUNC + memmove(&(node->data[i+1]), + &(node->data[i]), + (node->dataCount-i)*sizeof(void *)); + memmove(&(node->children[i+2]), + &(node->children[i+1]), + (node->dataCount-i)*sizeof(TreeNode *)); +#else int j = node->dataCount; for (; j > i; j--) { node->data[j] = node->data[j-1]; node->children[j+1] = node->children[j]; } +#endif - assert(!node->children[j] || - tree->compareData(data, node->children[j]->data[0]) > 0); + assert(!node->children[i] || + tree->compareData(data, node->children[i]->data[0]) > 0); - node->data[j] = data; - node->children[j+1] = newNode; + node->data[i] = data; + node->children[i+1] = newNode; node->dataCount++; } @@ -150,10 +225,7 @@ _AddDataToSplitNodes(Tree * tree, } int i = 0; - for (; - i < moreNode->dataCount && - tree->compareData(data, moreNode->data[i]) > 0; - i++); + _FindPositionInNode(tree, moreNode, data, &i); if (i == 0) { @@ -165,19 +237,28 @@ _AddDataToSplitNodes(Tree * tree, retData = moreNode->data[0]; } +#ifdef USE_MEM_FUNC + memmove(&(moreNode->data[0]), + &(moreNode->data[1]), + i*sizeof(void *)); + memmove(&(moreNode->children[0]), + &(moreNode->children[1]), + i*sizeof(TreeNode *)); +#else int j = 0; for (; j < i; j++) { moreNode->data[j] = moreNode->data[j+1]; moreNode->children[j] = moreNode->children[j+1]; } +#endif - assert(!moreNode->children[j-1] || + assert(!moreNode->children[i-1] || tree->compareData(data, - moreNode->children[j]->data[0]) > 0); + moreNode->children[i]->data[0]) > 0); - moreNode->data[j-1] = data; - moreNode->children[j] = newNode; + moreNode->data[i-1] = data; + moreNode->children[i] = newNode; } return retData; @@ -236,18 +317,90 @@ _InsertAt(TreeIterator * iter, void * data) return; } -void SetIteratorToBegin(TreeIterator * iter, Tree * tree) +static void _SetTreeIteratorToRoot(TreeIterator * iter, Tree * tree) { iter->tree = tree; iter->node = tree->rootNode; iter->which = 0; } +/************************* PUBLIC METHODS ***********************************/ + +Tree * +MakeTree(TreeCompareDataFunction compareData, TreeFreeDataFunction freeData) +{ + Tree * ret = malloc(sizeof(Tree)); + ret->compareData = compareData; + ret->freeData = freeData; + ret->rootNode = _MakeNode(); + return ret; +} + +void SetTreeIteratorToBegin(TreeIterator * iter, Tree * tree) +{ + _SetTreeIteratorToRoot(iter, tree); + IncrementTreeIterator(iter); +} + +int IsTreeIteratorAtEnd(const TreeIterator * iter) +{ + return (iter->node == NULL); +} + +void IncrementTreeIterator(TreeIterator * iter) +{ + while(iter->node) + { + if (iter->node->children[iter->which]) + { + iter->node = iter->node->children[iter->which]; + iter->which = 0; + } + else + { + iter->which++; + } + + while (iter->node && iter->which > iter->node->dataCount) + { + TreeNode * childNode = iter->node; + iter->node = childNode->parent; + if (iter->node) + { + for (iter->which = 0; + childNode != + iter->node->children[iter->which]; + iter->which++) + { + assert(iter->which <= + iter->node->dataCount); + } + iter->which++; + } + } + + if (iter->node && + iter->which > 0 && iter->which <= iter->node->dataCount) + { + return; + } + } +} + +void * +GetDataFromTreeIterator(TreeIterator * iter) +{ + assert(iter->node && + iter->which > 0 && + iter->which <= iter->node->dataCount); + return iter->node->data[iter->which-1]; +} + int InsertIntoTree(Tree * tree, void * data) { TreeIterator iter; - SetIteratorToBegin(&iter, tree); + _SetTreeIteratorToRoot(&iter, tree); if (_Find(&iter, data)) { |