Importing from busted CVS

master
Coleman 2008-07-02 23:44:56 -05:00
commit d10b87ef2b
5 changed files with 573 additions and 0 deletions

306
AVLTree.c Normal file
View File

@ -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;
}

18
Element.c Normal file
View File

@ -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);
}

11
Element.h Normal file
View File

@ -0,0 +1,11 @@
#ifndef __Element_H
#define __Element_H
typedef long *Element;
short Compare(Element Data1, Element Data2);
void FreeElement(Element Data);
#endif

55
Tree.h Normal file
View File

@ -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

183
main.c Normal file
View File

@ -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;
}