#include "tree.h" #include #include #include #include static TreeNode * _MakeNode() { TreeNode * ret = malloc(sizeof(TreeNode)); memset(ret, 0, sizeof(TreeNode)); return ret; } static int _Find(TreeIterator * iter, void * data) { while (1) { for (; iter->which < iter->node->dataCount; iter->which++) { int comp = iter->tree-> compareData(data,iter->node->data[iter->which]); if (comp == 0) { return 1; } else if (comp < 0) { break; } } assert(iter->which < CHILDREN_PER_NODE); if (iter->node->children[iter->which]) { iter->node = iter->node->children[iter->which]; iter->which = 0; } else { return 0; } } } 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) { assert(node->dataCount == DATA_PER_NODE); TreeNode * newNode = _MakeNode(); unsigned i = DATA_PER_NODE/2; unsigned j = 0; for (; i < DATA_PER_NODE; i++, j++) { newNode->data[j] = node->data[i]; newNode->children[j+1] = node->children[i+1]; 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; return newNode; } static void _InsertNodeAndData(Tree * tree, TreeNode * node, TreeNode * newNode, void * data) { assert(node->dataCount < DATA_PER_NODE); assert(!newNode || tree->compareData(data, newNode->data[0]) < 0); if (newNode) { newNode->parent = node; } int i = 0; for (; i < node->dataCount && tree->compareData(data, node->data[i]) > 0; i++); int j = node->dataCount; for (; j > i; j--) { node->data[j] = node->data[j-1]; node->children[j+1] = node->children[j]; } assert(!node->children[j] || tree->compareData(data, node->children[j]->data[0]) > 0); node->data[j] = data; node->children[j+1] = newNode; node->dataCount++; } static void * _AddDataToSplitNodes(Tree * tree, TreeNode * lessNode, TreeNode * moreNode, TreeNode * newNode, void * data) { assert(newNode == NULL || tree->compareData(data, newNode->data[0]) < 0); void * retData; if (tree->compareData(data, moreNode->data[0]) < 0) { _InsertNodeAndData(tree, lessNode, newNode, data); lessNode->dataCount--; retData = lessNode->data[lessNode->dataCount]; lessNode->data[lessNode->dataCount] = NULL; } else { if (newNode) { newNode->parent = moreNode; } int i = 0; for (; i < moreNode->dataCount && tree->compareData(data, moreNode->data[i]) > 0; i++); if (i == 0) { moreNode->children[0] = newNode; return data; } else { retData = moreNode->data[0]; } int j = 0; for (; j < i; j++) { moreNode->data[j] = moreNode->data[j+1]; moreNode->children[j] = moreNode->children[j+1]; } assert(!moreNode->children[j-1] || tree->compareData(data, moreNode->children[j]->data[0]) > 0); moreNode->data[j-1] = data; moreNode->children[j] = newNode; } return retData; } static void _InsertAt(TreeIterator * iter, void * data) { TreeNode * node = iter->node; TreeNode * insertNode = NULL; while (node != NULL) { // see if there's any NULL data in the current node if (node->dataCount == DATA_PER_NODE) { // no open data slots, split this node! TreeNode * newNode = _SplitNode(node); // insert data in split nodes data = _AddDataToSplitNodes(iter->tree, node, newNode, insertNode, data); insertNode = newNode; if (node->parent == NULL) { assert(node == iter->tree->rootNode); iter->tree->rootNode = _MakeNode(); node->parent = iter->tree->rootNode; newNode->parent = iter->tree->rootNode; iter->tree->rootNode->data[0] = data; iter->tree->rootNode->children[0] = node; iter->tree->rootNode->children[1] = newNode; iter->tree->rootNode->dataCount = 1; return; } node = node->parent; } else { // insert the data and newNode _InsertNodeAndData( iter->tree, node, insertNode, data ); node = NULL; } } return; } void SetIteratorToBegin(TreeIterator * iter, Tree * tree) { iter->tree = tree; iter->node = tree->rootNode; iter->which = 0; } int InsertIntoTree(Tree * tree, void * data) { TreeIterator iter; SetIteratorToBegin(&iter, tree); if (_Find(&iter, data)) { return 0; } _InsertAt(&iter, data); return 1; }