Importing from busted CVS
commit
d10b87ef2b
|
@ -0,0 +1,306 @@
|
|||
/*
|
||||
* A free AVLTree implementation written by Andrew Coleman
|
||||
* find out more cool things and licensing at http://penguincoder.org
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "Tree.h"
|
||||
|
||||
TreeNode *FindByElement(TreeNode *rootNode, Element Data)
|
||||
{
|
||||
short comp;
|
||||
TreeNode *Return;
|
||||
|
||||
/* sanity checks */
|
||||
if(Data == NULL)
|
||||
return NULL;
|
||||
else if(rootNode == NULL || rootNode->Item == NULL) {
|
||||
/* reached a leaf, and the data was not found */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* non recursive search because it really isn't neccessary right here */
|
||||
Return = rootNode;
|
||||
do {
|
||||
comp = Compare(Return->Item, Data);
|
||||
if(comp < 0)
|
||||
Return = Return->Left;
|
||||
else if(comp > 0)
|
||||
Return = Return->Right;
|
||||
} while(Return != NULL && comp != 0);
|
||||
return Return;
|
||||
}
|
||||
|
||||
short IsEmpty(TreeNode *rootNode)
|
||||
{
|
||||
return (rootNode == NULL);
|
||||
}
|
||||
|
||||
TreeNode *SingleRightRotation(TreeNode *rootNode)
|
||||
{
|
||||
TreeNode *newRoot = NULL;
|
||||
newRoot = rootNode->Left;
|
||||
rootNode->Left = newRoot->Right;
|
||||
newRoot->Right = rootNode;
|
||||
return newRoot;
|
||||
}
|
||||
|
||||
TreeNode *SingleLeftRotation(TreeNode *rootNode)
|
||||
{
|
||||
TreeNode *newRoot = NULL;
|
||||
newRoot = rootNode->Right;
|
||||
rootNode->Right = newRoot->Left;
|
||||
newRoot->Left = rootNode;
|
||||
return newRoot;
|
||||
}
|
||||
|
||||
TreeNode *DoubleRightRotation(TreeNode *rootNode)
|
||||
{
|
||||
TreeNode *newRoot = SingleLeftRotation(rootNode->Left);
|
||||
rootNode->Left = newRoot;
|
||||
newRoot = SingleRightRotation(rootNode);
|
||||
return newRoot;
|
||||
}
|
||||
|
||||
TreeNode *DoubleLeftRotation(TreeNode *rootNode)
|
||||
{
|
||||
TreeNode *newRoot = SingleRightRotation(rootNode->Right);
|
||||
rootNode->Right = newRoot;
|
||||
newRoot = SingleLeftRotation(rootNode);
|
||||
return newRoot;
|
||||
}
|
||||
|
||||
TreeNode *CheckTreeNodeRotation(TreeNode *tnode,
|
||||
TreeNode *subtree, short *finished)
|
||||
{
|
||||
/* this function will check to see if tnode's Balance factor indicates
|
||||
that a rotation is needed. Subtree is the child link that was either
|
||||
just added or possibly changed */
|
||||
switch(tnode->Balance) {
|
||||
case 0:
|
||||
/* nothing special, but we have balanced out properly, yay */
|
||||
*finished = 1;
|
||||
break;
|
||||
case 2:
|
||||
/* right heavy */
|
||||
*finished = 1;
|
||||
if(subtree->Balance == -1) {
|
||||
/* update balance factors */
|
||||
if(subtree->Left->Balance == 1) {
|
||||
subtree->Balance = 0;
|
||||
tnode->Balance = -1;
|
||||
} else if(subtree->Left->Balance == -1) {
|
||||
subtree->Balance = 1;
|
||||
tnode->Balance = 0;
|
||||
} else
|
||||
subtree->Balance = tnode->Balance = 0;
|
||||
subtree->Left->Balance = 0;
|
||||
tnode = DoubleLeftRotation(tnode);
|
||||
} else if(subtree->Balance == 1) {
|
||||
/* update balance factors */
|
||||
subtree->Balance = tnode->Balance = 0;
|
||||
tnode = SingleLeftRotation(tnode);
|
||||
}
|
||||
break;
|
||||
case -2:
|
||||
/* left heavy */
|
||||
*finished = 1;
|
||||
if(subtree->Balance == 1) {
|
||||
/* update balance factors */
|
||||
if(subtree->Right->Balance == -1) {
|
||||
subtree->Balance = 0;
|
||||
tnode->Balance = 1;
|
||||
} else if(subtree->Right->Balance == 1) {
|
||||
subtree->Balance = -1;
|
||||
tnode->Balance = 0;
|
||||
} else
|
||||
subtree->Balance = tnode->Balance = 0;
|
||||
subtree->Right->Balance = 0;
|
||||
tnode = DoubleRightRotation(tnode);
|
||||
} else if(subtree->Balance == -1) {
|
||||
/* update balance factors */
|
||||
subtree->Balance = tnode->Balance = 0;
|
||||
tnode = SingleRightRotation(tnode);
|
||||
}
|
||||
}
|
||||
return tnode;
|
||||
}
|
||||
|
||||
TreeNode *InsertNode(TreeNode *tnode, Element Item,
|
||||
char *Name, short *finished)
|
||||
{
|
||||
TreeNode *subtree = NULL;
|
||||
short comp = 0;
|
||||
|
||||
if(tnode == NULL) {
|
||||
/* found the spot that the TreeNode belongs */
|
||||
tnode = malloc(sizeof(TreeNode));
|
||||
/* malloc problem, return NULL */
|
||||
if(tnode == NULL)
|
||||
return NULL;
|
||||
else {
|
||||
/* default settings for a new node */
|
||||
tnode->Left = NULL;
|
||||
tnode->Right = NULL;
|
||||
tnode->Item = Item;
|
||||
tnode->Name = Name;
|
||||
tnode->Balance = 0;
|
||||
}
|
||||
} else {
|
||||
/* need to find the new node, don't check for a 0,
|
||||
cos its already in teh tree, foo */
|
||||
comp = Compare(Item, tnode->Item);
|
||||
if(comp < 0) {
|
||||
/* go left */
|
||||
subtree = InsertNode(tnode->Left, Item, Name, finished);
|
||||
/* if this is NULL, there is problem. quit now */
|
||||
if(subtree == NULL)
|
||||
return NULL;
|
||||
/* you are not finished until Balance == 0, reached the root
|
||||
or a rotation has occured */
|
||||
if(!*finished)
|
||||
tnode->Balance--;
|
||||
tnode->Left = subtree;
|
||||
} else if(comp > 0) {
|
||||
/* go right */
|
||||
subtree = InsertNode(tnode->Right, Item, Name, finished);
|
||||
if(subtree == NULL)
|
||||
return NULL;
|
||||
if(!*finished)
|
||||
tnode->Balance++;
|
||||
tnode->Right = subtree;
|
||||
} else
|
||||
/* got a dupe, return NULL */
|
||||
return NULL;
|
||||
|
||||
/* check if a rotation is neccessary */
|
||||
if(!*finished) {
|
||||
tnode = CheckTreeNodeRotation(tnode, subtree, finished);
|
||||
}
|
||||
}
|
||||
return tnode;
|
||||
}
|
||||
|
||||
TreeNode *Insert(TreeNode *tnode, Element Item, char *Name)
|
||||
{
|
||||
/* flag for the recursive function */
|
||||
short done = 0;
|
||||
/* run and return the recursive insert */
|
||||
return InsertNode(tnode, Item, Name, &done);
|
||||
}
|
||||
|
||||
void MakeEmpty(TreeNode *rootNode)
|
||||
{
|
||||
/* this function is pretty simple, just traverses the tree and starts
|
||||
free'ing from the bottom up */
|
||||
if(rootNode == NULL)
|
||||
return;
|
||||
MakeEmpty(rootNode->Left);
|
||||
MakeEmpty(rootNode->Right);
|
||||
FreeElement(rootNode->Item);
|
||||
free(rootNode->Name);
|
||||
free(rootNode);
|
||||
}
|
||||
|
||||
TreeNode *DeleteLeftMost(TreeNode **deletedNode, TreeNode *rootNode,
|
||||
short *finished)
|
||||
{
|
||||
TreeNode *subtree = rootNode->Right;
|
||||
if(rootNode == NULL) {
|
||||
printf("bailing!\n");
|
||||
return NULL;
|
||||
}
|
||||
if(rootNode->Left == NULL) {
|
||||
free((*deletedNode)->Name);
|
||||
FreeElement((*deletedNode)->Item);
|
||||
(*deletedNode)->Name = rootNode->Name;
|
||||
(*deletedNode)->Item = rootNode->Item;
|
||||
free(rootNode);
|
||||
rootNode = subtree;
|
||||
} else {
|
||||
rootNode->Left = DeleteLeftMost(deletedNode, rootNode->Left, finished);
|
||||
if(!*finished) {
|
||||
rootNode->Balance++;
|
||||
if(rootNode->Left != NULL)
|
||||
rootNode = CheckTreeNodeRotation(rootNode, rootNode->Left,
|
||||
finished);
|
||||
}
|
||||
}
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
TreeNode *DeleteByElementRecursive(TreeNode *rootNode,
|
||||
Element Item, short *finished)
|
||||
{
|
||||
TreeNode *subtree = NULL;
|
||||
short comp = 0;
|
||||
|
||||
/* found a leaf */
|
||||
if(rootNode == NULL)
|
||||
return NULL;
|
||||
/* figure out where the node in question is in relation to the current */
|
||||
comp = Compare(rootNode->Item, Item);
|
||||
if(comp > 0) {
|
||||
/* buried somewhere in the right subtree */
|
||||
subtree = DeleteByElementRecursive(rootNode->Right, Item, finished);
|
||||
rootNode->Right = subtree;
|
||||
if(!*finished && subtree != NULL) {
|
||||
rootNode->Balance--;
|
||||
rootNode = CheckTreeNodeRotation(rootNode, subtree, finished);
|
||||
}
|
||||
} else if(comp < 0) {
|
||||
subtree = DeleteByElementRecursive(rootNode->Left, Item, finished);
|
||||
rootNode->Left = subtree;
|
||||
if(!*finished && subtree != NULL) {
|
||||
rootNode->Balance++;
|
||||
rootNode = CheckTreeNodeRotation(rootNode, subtree, finished);
|
||||
}
|
||||
} else {
|
||||
/* found what we were looking for */
|
||||
if(rootNode->Right == NULL) {
|
||||
/* rootNode is replaced by the left child; can be null */
|
||||
subtree = rootNode->Left;
|
||||
free(rootNode->Name);
|
||||
FreeElement(rootNode->Item);
|
||||
free(rootNode);
|
||||
rootNode = subtree;
|
||||
} else if(rootNode->Right->Left == NULL) {
|
||||
/* rootNode is replaced by Right */
|
||||
subtree = rootNode->Right;
|
||||
subtree->Balance = rootNode->Balance;
|
||||
subtree->Left = rootNode->Left;
|
||||
free(rootNode->Name);
|
||||
FreeElement(rootNode->Item);
|
||||
free(rootNode);
|
||||
rootNode = subtree;
|
||||
} else {
|
||||
/* rootNode is replaced by inorder successor */
|
||||
/* re-using comp as another flag since it is 0 */
|
||||
rootNode->Right = DeleteLeftMost(&rootNode, rootNode->Right, &comp);
|
||||
}
|
||||
}
|
||||
return rootNode;
|
||||
}
|
||||
|
||||
TreeNode *DeleteByElement(TreeNode *rootNode, Element Item)
|
||||
{
|
||||
short finished = 0;
|
||||
TreeNode *newRoot = NULL;
|
||||
newRoot = DeleteByElementRecursive(rootNode, Item, &finished);
|
||||
return newRoot;
|
||||
}
|
||||
|
||||
long Height(TreeNode *rootNode)
|
||||
{
|
||||
/* recursive function to determine the height by comparing the height of
|
||||
the left and right child and returning the larger value */
|
||||
long lresult = 0, rresult = 0;
|
||||
/* either the tree is empty or we found a leaf */
|
||||
if(rootNode == NULL)
|
||||
return 0;
|
||||
lresult = Height(rootNode->Left);
|
||||
rresult = Height(rootNode->Right);
|
||||
/* minimum height is 1, but that's probably correct */
|
||||
return (lresult > rresult ? lresult : rresult) + 1;
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "Element.h"
|
||||
|
||||
short Compare(Element Data1, Element Data2)
|
||||
{
|
||||
if(*Data1 > *Data2)
|
||||
return 1;
|
||||
else if(*Data1 < *Data2)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void FreeElement(Element Data)
|
||||
{
|
||||
free(Data);
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
#ifndef __Element_H
|
||||
|
||||
#define __Element_H
|
||||
|
||||
typedef long *Element;
|
||||
|
||||
short Compare(Element Data1, Element Data2);
|
||||
|
||||
void FreeElement(Element Data);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,55 @@
|
|||
#ifndef __Tree_H
|
||||
|
||||
#define __Tree_H
|
||||
|
||||
#include "Element.h"
|
||||
|
||||
/* the basic tree structure
|
||||
* the root of the complete tree is defined where Parent is NULL
|
||||
*/
|
||||
typedef struct TreeNodeTag {
|
||||
struct TreeNodeTag *Left;
|
||||
struct TreeNodeTag *Right;
|
||||
Element Item;
|
||||
char *Name;
|
||||
short Balance;
|
||||
} TreeNode;
|
||||
|
||||
/*
|
||||
* This function will find a particular TreeNode with the given
|
||||
* Element as the Item.
|
||||
*/
|
||||
TreeNode *FindByElement(TreeNode *rootNode, const Element item);
|
||||
|
||||
/*
|
||||
* This function will return a boolean and determine if the given tree
|
||||
* (or subtree) is empty.
|
||||
*/
|
||||
short IsEmpty(TreeNode *rootNode);
|
||||
|
||||
/*
|
||||
* This function will insert a given Element into the tree (subtree) and
|
||||
* perform all neccessary adjustments to the tree. Returns the new root
|
||||
* node.
|
||||
*/
|
||||
TreeNode *Insert(TreeNode *rootNode, Element Item, char *Name);
|
||||
|
||||
/*
|
||||
* This function will remove all items from the give tree or subtree
|
||||
*/
|
||||
void MakeEmpty(TreeNode *rootNode);
|
||||
|
||||
/*
|
||||
* Deletes a given TreeNode and will perform all neccessary adjustments
|
||||
* to the tree. Returns the new root node. Note: the Name field will be
|
||||
* free'd with the TreeNode.
|
||||
*/
|
||||
TreeNode *DeleteByElement(TreeNode *rootNode, Element Item);
|
||||
|
||||
/*
|
||||
* Determines the height of the given tree. Should be used with caution with
|
||||
* large trees.
|
||||
*/
|
||||
long Height(TreeNode *rootNode);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,183 @@
|
|||
/* A balanced binary search tree(AVLTree) implementation
|
||||
* Written by Coleman
|
||||
* Released under GNU GPL Version 2 or later(http://www.gnu.org/)
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "Element.h"
|
||||
#include "Tree.h"
|
||||
|
||||
#define MAXELEMENTSIZE 500000
|
||||
|
||||
int calcsize(TreeNode *tnode) {
|
||||
long result = 0;
|
||||
if(tnode == NULL)
|
||||
return 0;
|
||||
result = sizeof(tnode);
|
||||
result +=(long)sizeof(Element);
|
||||
result +=(long)sizeof(char) * strlen(tnode->Name);
|
||||
result += calcsize(tnode->Left);
|
||||
result += calcsize(tnode->Right);
|
||||
return result;
|
||||
}
|
||||
|
||||
void printTree(TreeNode *start, long level)
|
||||
{
|
||||
long i = 0;
|
||||
if(start == NULL)
|
||||
return;
|
||||
printf("%s -> %ld, Balance %d\n", start->Name,
|
||||
*start->Item, start->Balance);
|
||||
for(i = 0; i < level; i++)
|
||||
printf(" ");
|
||||
printf("Left: ");
|
||||
printTree(start->Left, level + 1);
|
||||
printf("\n");
|
||||
for(i = 0; i < level; i++)
|
||||
printf(" ");
|
||||
printf("Right: ");
|
||||
printTree(start->Right, level + 1);
|
||||
if(level == 0)
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
long breadth(TreeNode *start)
|
||||
{
|
||||
if(start == NULL)
|
||||
return (long)0;
|
||||
if(start->Left == NULL && start->Right == NULL)
|
||||
return (long)1;
|
||||
return (long)(breadth(start->Left) + breadth(start->Right));
|
||||
}
|
||||
|
||||
int main(int argc, char** argv)
|
||||
{
|
||||
TreeNode *tree = NULL, *newTree = NULL;
|
||||
Element newItem = NULL;
|
||||
char *itemName = NULL;
|
||||
long i = 0, topsize = 0, tick = 0, last = 0;
|
||||
long height = 0, oldheight = 0;
|
||||
|
||||
/* get the command argument, used for a custom size parameter */
|
||||
if(argc == 2)
|
||||
topsize = atol(argv[1]);
|
||||
if(topsize == 0 || topsize > MAXELEMENTSIZE)
|
||||
topsize = 25;
|
||||
tick = topsize / 20;
|
||||
|
||||
srand48((long)time(NULL));
|
||||
printf("Start --> Finished\n");
|
||||
for(i = 0; i < topsize; i++) {
|
||||
newItem = malloc(sizeof(Element));
|
||||
itemName = malloc(sizeof(char) * 11);
|
||||
sprintf(itemName, "Name%ld", i);
|
||||
do {
|
||||
*newItem = lrand48();
|
||||
newTree = Insert(tree, newItem, itemName);
|
||||
if(newTree == NULL) {
|
||||
if(last == *newItem) {
|
||||
free(itemName);
|
||||
free(newItem);
|
||||
printf("going to try and skip: %ld\n", *newItem);
|
||||
break;
|
||||
} else
|
||||
last = *newItem;
|
||||
}
|
||||
} while(newTree == NULL);
|
||||
if(i % tick == 0) {
|
||||
printf(".");
|
||||
fflush(stdout);
|
||||
}
|
||||
tree = newTree;
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
/* test out the delete functionality */
|
||||
printf("\nGoing to delete the rootNode: %ld\n", *tree->Item);
|
||||
newTree = DeleteByElement(tree, tree->Item);
|
||||
if(newTree == NULL)
|
||||
printf("failure!\n");
|
||||
else {
|
||||
tree = newTree;
|
||||
printf("success! new root is %ld\n", *tree->Item);
|
||||
}
|
||||
printf("\nGoing to delete leftMost child... ");
|
||||
for(newTree = tree;
|
||||
newTree != NULL && newTree->Left != NULL;
|
||||
newTree = newTree->Left) {}
|
||||
if(newTree != NULL) {
|
||||
printf("found item: %ld\n", *newTree->Item);
|
||||
newTree = DeleteByElement(tree, newTree->Item);
|
||||
if(newTree == NULL)
|
||||
printf("failure!\n");
|
||||
else {
|
||||
printf("success! new root: %ld\n", *newTree->Item);
|
||||
tree = newTree;
|
||||
}
|
||||
}
|
||||
/* duplicated from left side */
|
||||
printf("\nGoing to delete rightMost child... ");
|
||||
for(newTree = tree;
|
||||
newTree != NULL && newTree->Right != NULL;
|
||||
newTree = newTree->Right) {}
|
||||
if(newTree != NULL) {
|
||||
printf("found item: %ld\n", *newTree->Item);
|
||||
newTree = DeleteByElement(tree, newTree->Item);
|
||||
if(newTree == NULL)
|
||||
printf("failure!\n");
|
||||
else {
|
||||
printf("success! new root: %ld\n", *newTree->Item);
|
||||
tree = newTree;
|
||||
}
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
if(topsize <= 25)
|
||||
printTree(tree, 0);
|
||||
printf("sizeof(TreeNode) %d\n",(int)sizeof(TreeNode));
|
||||
printf("sizeof(Element) %d\n",(int)sizeof(Element));
|
||||
printf("sizeof(tree) %d\n", calcsize(tree));
|
||||
printf("breadth of left tree: %ld right subtree: %ld\n",
|
||||
breadth(tree->Left), breadth(tree->Right));
|
||||
oldheight = Height(tree->Left);
|
||||
printf("height of left subtree: %ld right subtree: %ld\n",
|
||||
oldheight, Height(tree->Right));
|
||||
|
||||
last = (long)(LONG_MAX / 2);
|
||||
for(i = 0; i < 3; i++) {
|
||||
printf("\n");
|
||||
height = lrand48() % oldheight;
|
||||
printf("Going to delete a node at depth (max depth %ld): %ld\n",
|
||||
oldheight, height);
|
||||
newTree = tree;
|
||||
do {
|
||||
if(newTree->Left == NULL) {
|
||||
if(newTree->Right == NULL)
|
||||
break;
|
||||
tick = last + 1;
|
||||
} else if(newTree->Right == NULL)
|
||||
tick = last - 1;
|
||||
else
|
||||
tick = lrand48();
|
||||
newTree = (tick >= last ? newTree->Right : newTree->Left);
|
||||
height--;
|
||||
} while(height > 0);
|
||||
printf("Found a node to delete with Name '%s' and Item %ld\n",
|
||||
newTree->Name, *newTree->Item);
|
||||
newTree = DeleteByElement(tree, newTree->Item);
|
||||
if(newTree == NULL)
|
||||
printf("failure!\n");
|
||||
else {
|
||||
printf("success! new root: %ld\n", *newTree->Item);
|
||||
tree = newTree;
|
||||
}
|
||||
oldheight = (int)(oldheight * 0.6);
|
||||
}
|
||||
|
||||
MakeEmpty(tree);
|
||||
return 0;
|
||||
}
|
Reference in New Issue