Article View: comp.sw.components
Article #366Re: What is a reusable software component?
From: Paul Sander
Date: Sat, 18 Aug 1990 04:38
Date: Sat, 18 Aug 1990 04:38
2386 lines
57912 bytes
57912 bytes
Here is the updated implementation of the in-memory B-tree that has been
used as sample code for this thread. Please see the related posting
identified as <28982@athertn.Atherton.COM>.
----------
#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
# btpriv.h
# btree.h
# bt_last.c
# bt_next.c
# bt_prev.c
# btdelete.c
# btdestroy.c
# btdump.c
# btfirst.c
# btinsert.c
# btmalloc.c
# btnew.c
# btsearch.c
# bttraverse.c
# btutil.c
# test.c
# This archive created: Fri Aug 17 20:48:43 1990
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'btpriv.h'
then
echo shar: "will not over-write existing file 'btpriv.h'"
else
cat << \SHAR_EOF > 'btpriv.h'
/* The following structure describes a B-tree node. */
struct btnode {
int nkeys; /* Number of keys stored here */
int currKey; /* Last key found */
struct btnode *parent; /* Parent of this node */
char **keys; /* array[order-1] of keys */
struct btnode **children; /* array[order] of children */
};
/* The following structure describes a B-tree. */
struct btree {
int order; /* Max children permitted */
int (*comp)(); /* Comparison function for keys */
struct btnode *root; /* Root of tree */
int capacity; /* Max keys that will fit */
int contains; /* Key currently stored */
struct btnode *currNode; /* Node accessed */
int nextOk; /* Indicates last search successful */
};
typedef struct btree *BTREE;
typedef struct btnode BTNODE;
#ifndef DEBUG
#define bt_malloc malloc
#define bt_free free
#else
extern char *bt_malloc();
extern char *bt_free();
#endif
extern bt_malloc_verify();
#ifdef __BTUTIL_C__
extern int bt_searchNode();
extern int bt_rotateRight();
extern int bt_rotateLeft();
#endif
SHAR_EOF
fi
if test -f 'btree.h'
then
echo shar: "will not over-write existing file 'btree.h'"
else
cat << \SHAR_EOF > 'btree.h'
/* Header file for in-memory B-tree implementation */
typedef char *BTREE;
extern void bt_dump();
extern char *bt_search();
extern BTREE bt_new();
extern void bt_destroy();
extern int bt_insert();
extern void bt_traverse();
extern char *bt_delete();
extern char *bt_first();
extern char *bt_next();
extern char *bt_last();
extern char *bt_prev();
SHAR_EOF
fi
if test -f 'bt_last.c'
then
echo shar: "will not over-write existing file 'bt_last.c'"
else
cat << \SHAR_EOF > 'bt_last.c'
/********************************************************************
*
* bt_last.c -- This file contains functions needed to find the
* key that is highest in the lexical order of keys
* stored in an in-memory B-tree.
********************************************************************/
#include <stdio.h>
#include "btpriv.h"
/********************************************************************
*
* bt_last -- This function returns the key that appears last in
* the lexical order of the items stored in the tree.
* NULL is returned if the tree is empty.
*
*******************************************************************/
char *bt_last(tree)
BTREE tree;
{
BTNODE *node;
if (tree == NULL) return NULL;
node = tree->root;
if (node->nkeys == 0) return NULL;
while (node->children != NULL)
{
node->currKey = node->nkeys;
node = node->children[node->nkeys];
}
node->currKey = node->nkeys - 1;
tree->currNode = node;
tree->nextOk = 1;
return node->keys[node->nkeys - 1];
}
SHAR_EOF
fi
if test -f 'bt_next.c'
then
echo shar: "will not over-write existing file 'bt_next.c'"
else
cat << \SHAR_EOF > 'bt_next.c'
/********************************************************************
*
* bt_next.c -- This file contains functions needed to scan an in-memory
* B-tree in ascending order.
*
********************************************************************/
#include <stdio.h>
#include "btpriv.h"
/********************************************************************
*
* bt_next -- This function returns the key that appears next in
* the lexical order of the items stored in the tree,
* after the last bt_search, bt_next, bt_prev, bt_last,
* or bt_first. NULL is returned if the tree is empty, an
* insertion or deletion invalidated the state of the
* tree, or the last item in the tree was already visited.
*
*******************************************************************/
char *bt_next(tree)
BTREE tree;
{
BTNODE *node;
int key;
/* Return if error, or insertion/deletion invalidated state */
if ((tree == NULL) || (tree->currNode == NULL)) return NULL;
/* Set up temporaries */
node = tree->currNode;
key = node->currKey;
/* Return if we've overrun the tree */
if (key >= node->nkeys) return NULL;
/*
* Bump current key in current node, compensating for unsuccessful
* search
*/
if (tree->nextOk) key++;
tree->nextOk = 1;
/* If node has children, return leftmost key of next child */
if (node->children != NULL)
{
node->currKey = key;
node = node->children[key];
while (node->children != NULL)
{
node->currKey = 0;
node = node->children[0];
}
node->currKey = 0;
tree->currNode = node;
return node->keys[0];
}
/* Leaf node, return next key */
if (key < node->nkeys)
{
node->currKey = key;
return node->keys[key];
}
/* Already visited rightmost key of leaf, go back to parent */
while ((node->parent != NULL) && (key >= node->nkeys))
{
node = node->parent;
key = node->currKey;
}
/* Return NULL after last key in tree */
if (key >= node->nkeys)
{
tree->currNode = node;
node->currKey = key;
return NULL;
}
/* Return next key in parent */
tree->currNode = node;
return node->keys[key];
}
SHAR_EOF
fi
if test -f 'bt_prev.c'
then
echo shar: "will not over-write existing file 'bt_prev.c'"
else
cat << \SHAR_EOF > 'bt_prev.c'
/********************************************************************
*
* btprev.c -- This file contains functions needed to scan an in-memory
* B-tree in descending order.
*
********************************************************************/
#include <stdio.h>
#include "btpriv.h"
/********************************************************************
*
* bt_prev -- This function returns the next key that appears
* earlier in the lexical order of the items stored in
* the tree, after the last bt_search, bt_next, bt_prev, or
* bt_last. NULL is returned if the tree is empty, an
* insertion or deletion invalidated the state of the
* tree, or the next item in the tree was already visited.
*
*******************************************************************/
char *bt_prev(tree)
BTREE tree;
{
BTNODE *node;
int key;
/* Return if error, or insertion/deletion invalidated state */
if ((tree == NULL) || (tree->currNode == NULL)) return NULL;
tree->nextOk = 1;
/* Set up temporaries */
node = tree->currNode;
key = node->currKey;
/* Return if we've overrun the tree */
if (key < 0) return NULL;
/*
* If node has children, return rightmost key of previous
* child
*/
if (node->children != NULL)
{
node = node->children[key];
while (node->children != NULL)
{
node->currKey = node->nkeys;
node = node->children[node->nkeys];
}
node->currKey = node->nkeys - 1;
tree->currNode = node;
return node->keys[node->currKey];
}
/* Leaf node, return previous key */
key--;
if (key >= 0)
{
node->currKey = key;
return node->keys[key];
}
/* Already visited leftmost key of node, go back to parent */
while ((node->parent != NULL) && (key < 0))
{
node = node->parent;
key = node->currKey - 1;
}
/* Return NULL after last key in tree */
if (key < 0)
{
node->currKey = -1;
tree->currNode = node;
return NULL;
}
/* Return next key in parent */
node->currKey = key;
tree->currNode = node;
return node->keys[key];
}
SHAR_EOF
fi
if test -f 'btdelete.c'
then
echo shar: "will not over-write existing file 'btdelete.c'"
else
cat << \SHAR_EOF > 'btdelete.c'
/********************************************************************
*
* btdelete.c -- This file contains functions needed to delete a key
* from an in-memory B-tree.
*
********************************************************************/
#include <stdio.h>
#include "btpriv.h"
/********************************************************************
*
* bt_delKey -- This function deletes the specified key from the
* specified node.
*
********************************************************************/
static bt_delKey(node,n)
BTNODE *node;
int n;
{
int i;
for (i = n; i < node->nkeys - 1; i++)
{
node->keys[i] = node->keys[i+1];
}
if (node->children != NULL)
{
for (i = n; i < node->nkeys; i++)
{
node->children[i] = node->children[i+1];
}
}
node->nkeys--;
return;
}
/********************************************************************
*
* bt_weld -- This function is the opposite of burst, above. It joins
* two neighboring children of the given node, and lowers a
* key into the result.
*
********************************************************************/
static bt_weld(tree,node,n)
BTREE tree;
BTNODE *node;
int n;
{
int i;
int j;
BTNODE *left;
BTNODE *right;
if (node->children == NULL) return;
left = node->children[n];
right = node->children[n+1];
i = left->nkeys;
left->keys[i] = node->keys[n];
for (i++, j = 0; j < right->nkeys; i++, j++)
{
left->keys[i] = right->keys[j];
}
for (i = n + 1; i <= node->nkeys; i++)
{
node->keys[i-1] = node->keys[i];
node->children[i] = node->children[i+1];
}
node->nkeys--;
if (left->children != NULL)
{
for (i = left->nkeys + 1, j = 0; j <= right->nkeys; i++, j++)
{
left->children[i] = right->children[j];
left->children[i]->parent = left;
}
bt_free(right->children);
}
left->nkeys += right->nkeys + 1;
bt_free(right->keys);
bt_free(right);
tree->capacity -= tree->order - 1;
return;
}
/********************************************************************
*
* bt_delPred -- This function searches a sub-tree, and deletes the
* highest key it finds, and returns it to its caller.
* If any node along the way loses its b-tree'ness, the
* tree is reorganized after the deletion.
*
********************************************************************/
static char *bt_delPred(tree,node)
BTREE tree;
BTNODE *node;
{
BTNODE *pnode;
int res;
char *retval;
/*
* If at a leaf node, delete the highest key, otherwise
* call self recursively
*/
if (node->children == NULL)
{
retval = node->keys[node->nkeys - 1];
node->nkeys--;
}
else
{
pnode = node->children[node->nkeys];
retval = bt_delPred(tree,pnode);
/* Reorganize tree if node gets too empty */
if (pnode->nkeys < (tree->order - 1) / 2)
{
res = bt_rotateRight(node,node->nkeys - 1,tree->order);
if (res == 0) bt_weld(tree,node,node->nkeys - 1);
}
}
return retval;
}
/********************************************************************
*
* bt_delNode -- This function searches a sub-tree for a key, and
* deletes the key. If the key is found in a leaf node,
* it is simple removed and returned to the caller;
* otherwise, it is swapped with its predecessor, and
* the returned to the caller. If any node loses its
* b-tree'ness, the tree is reorganized. If the key is
* not found, NULL is returned.
*
********************************************************************/
static char *bt_delNode(tree,node,key)
BTREE tree;
BTNODE *node;
char *key;
{
int i;
int res;
char *retval;
/* Key not found */
if (node == NULL) return NULL;
/* Search for key, descend tree until found or find leaf */
i = bt_searchNode(node,key,tree->comp,&res);
if (res == 0)
{
if (node->children == NULL) return NULL;
retval = bt_delNode(tree,node->children[i],key);
}
else
{
/* Return the deleted node to caller */
retval = node->keys[i];
if (node->children == NULL)
{
/* Delete from leaf */
bt_delKey(node,i);
}
else
{
/* Swap with predecessor */
node->keys[i] = bt_delPred(tree,node->children[i]);
}
}
/* If a child node was reorganized, rebalancing may be necessary */
if ((node->children != NULL) &&
(node->children[i]->nkeys < (tree->order - 1) / 2))
{
res = bt_rotateRight(node,i - 1,tree->order);
if (res == 0) res = bt_rotateLeft(node,i,tree->order);
if (res == 0)
{
if (i >= node->nkeys) i--;
bt_weld(tree,node,i);
}
}
return retval;
}
/********************************************************************
*
* bt_delete -- This function deletes the specified key from a
* b-tree and reorganizes it as necessary. The deleted
* key is returned to the caller if it is found, NULL
* is returned otherwise.
*
********************************************************************/
char *bt_delete(ptree,key)
char *ptree;
char *key;
{
BTNODE *root;
char *retval;
BTREE tree;
tree = (BTREE) ptree;
/* Do no deletion if tree is empty */
root = tree->root;
if (root->nkeys == 0) return NULL;
/* Delete the key */
retval = bt_delNode(tree,root,key);
/*
* Delete the root if it is empty, yet its children are not.
* This happens after a weld on the last key in the root.
*/
if ((root->nkeys == 0) && (root->children != NULL))
{
tree->root = root->children[0];
bt_free(root->keys);
bt_free(root->children);
bt_free(root);
tree->capacity -= tree->order - 1;
tree->root->parent = NULL;
}
if (retval != NULL)
{
tree->contains--;
tree->currNode = NULL;
}
return retval;
}
SHAR_EOF
fi
if test -f 'btdestroy.c'
then
echo shar: "will not over-write existing file 'btdestroy.c'"
else
cat << \SHAR_EOF > 'btdestroy.c'
/********************************************************************
*
* btdestroy.c -- This function contains functions needed to deallocate
* an in-memory B-tree in its entirety.
*
********************************************************************/
#include <stdio.h>
#include "btpriv.h"
/********************************************************************
*
* bt_freeNode -- This function frees a node in a b-tree. It is
* provided with a function that frees each key in the
* node also. The free_key function has the following
* protocol:
*
* free_key(key)
* char *key;
*
* If NULL is passed as the free_key function, the node
* is freed, but no action is taken for the keys.
*
********************************************************************/
static void bt_freeNode(node,free_key)
BTNODE *node;
void (*free_key)();
{
int i;
if (node->children != NULL)
{
for (i = 0; i <= node->nkeys; i++)
{
bt_freeNode(node->children[i],free_key);
}
bt_free(node->children);
}
if (free_key != NULL)
{
for (i = 0; i < node->nkeys; i++)
{
(*free_key)(node->keys[i]);
}
}
bt_free(node->keys);
bt_free(node);
return;
}
/********************************************************************
*
* bt_destroy -- This function frees a b-tree structure. It is also
* passed a function that frees the keys contained by the
* tree. The free_key function has the same calling
* protocol as the free_key function passed to bt_freeNode
* above.
*
********************************************************************/
void bt_destroy(ptree,free_key)
char *ptree;
void (*free_key)();
{
BTREE tree;
tree = (BTREE) ptree;
bt_freeNode(tree->root,free_key);
bt_free(tree);
return;
}
SHAR_EOF
fi
if test -f 'btdump.c'
then
echo shar: "will not over-write existing file 'btdump.c'"
else
cat << \SHAR_EOF > 'btdump.c'
/*********************************************************************
*
* btdump.c -- This function contains functions needed to display
* the contents of an in-memory B-tree, passing each key
* to a callback function. This file contains non-portable
* code that is intended to help debug the B-tree
* implementation.
*
*********************************************************************/
#include <stdio.h>
#include "btpriv.h"
/*********************************************************************
*
* bt_dumpNode -- This function displays the contents of a node and
* then recursively displays its children. Note
* that this function assumes that a pointer to a node
* is the same size as an integer.
*
*********************************************************************/
void bt_dumpNode(node,key_dump)
BTNODE *node;
void (*key_dump)();
{
int i;
if (node == NULL)
{
printf("ERROR: null node pointer\n");
return;
}
printf("%08x: %d keys (keys %08x, children %08x), currKey = %d,\n",
(int) node,node->nkeys,node->keys,node->children,node->currKey);
printf("parent = %08x\n", (int) node->parent);
printf("--------\n");
for (i = 0; i < node->nkeys; i++)
{
if (node->children != NULL)
{
printf(" %08x\n",node->children[i]);
}
else
{
printf(" %08x\n",0);
}
if (key_dump != NULL)
{
printf(" ");
(*key_dump)(node->keys[i]);
}
}
if (node->children != NULL)
{
printf(" %08x\n",node->children[i]);
for (i = 0; i <= node->nkeys; i++)
{
bt_dumpNode(node->children[i],key_dump);
}
}
else
{
printf(" %08x\n",0);
}
fflush(stdout);
return;
}
/*********************************************************************
*
* bt_dump -- This function displays the contents of a B-tree. The
* caller passes in a function that displays the contents
* of one of the keys stored in the tree. The calling
* protocol for this function is:
*
* key_dump(key)
* char *key;
*
* Also, if key_dump is NULL, no action is taken. This is
* useful if the structure of the tree is desired without
* including its contents.
*
*********************************************************************/
void bt_dump(ptree,key_dump)
char *ptree;
void (*key_dump)();
{
BTREE tree;
tree = (BTREE) ptree;
printf("B-tree dump:\n\n");
printf("order = %d\n",tree->order);
printf("capacity = %d\n",tree->capacity);
printf("contains %d keys\n",tree->contains);
printf("efficiency is %d per cent\n",
(tree->contains*100)/tree->capacity);
printf("handle at %08x\n",tree);
printf("root = %08x\n\n",(int) tree->root);
printf("currNode = %08x\n\n",(int) tree->currNode);
bt_dumpNode(tree->root,key_dump);
return;
}
SHAR_EOF
fi
if test -f 'btfirst.c'
then
echo shar: "will not over-write existing file 'btfirst.c'"
else
cat << \SHAR_EOF > 'btfirst.c'
/********************************************************************
*
* btfirst.c -- This file contains functions to locate the key
* falling first in the lexical order of items stored
* in an in-memory B-tree.
*
********************************************************************/
#include <stdio.h>
#include "btpriv.h"
/********************************************************************
*
* bt_first -- This function returns the key that appears first in
* the lexical order of the items stored in the tree.
* NULL is returned if the tree is empty.
*
*******************************************************************/
char *bt_first(tree)
BTREE tree;
{
BTNODE *node;
if (tree == NULL) return NULL;
node = tree->root;
if (node->nkeys == 0) return NULL;
while (node->children != NULL)
{
node->currKey = 0;
node = node->children[0];
}
node->currKey = 0;
tree->currNode = node;
tree->nextOk = 1;
return node->keys[0];
}
SHAR_EOF
fi
if test -f 'btinsert.c'
then
echo shar: "will not over-write existing file 'btinsert.c'"
else
cat << \SHAR_EOF > 'btinsert.c'
/*********************************************************************
*
* btinsert.c -- This file contains functions needed to insert new
* items into an in-memory B-tree.
*
*********************************************************************/
#include <stdio.h>
#include "btpriv.h"
/*********************************************************************
*
* bt_insertKey -- This function inserts a key into a specified node at
* a specified location in its key array. 0 is returned
* if the node is already full, 1 otherwise.
*
*********************************************************************/
static int bt_insertKey(node,key,n,order)
BTNODE *node;
char *key;
int n;
int order;
{
int i;
/* Return FALSE if insertion is not possible */
if (node->nkeys >= order - 1)
{
return 0;
}
/* Shift keys to make room, then insert new key */
for (i = node->nkeys - 1; i >= n; i--)
{
node->keys[i+1] = node->keys[i];
}
node->keys[n] = key;
node->nkeys++;
return 1;
}
/*********************************************************************
*
* bt_burst -- Given a node and an index into its key and child arrays,
* this function splits the specified child node in half,
* elevating the key at the child's split point into this
* specified node. 0 is returned if the child array index
* is out of range, or the node is full, or malloc fails;
* 1 is returned otherwise.
*
*********************************************************************/
static int bt_burst(tree,node,n)
BTREE tree;
BTNODE *node;
int n;
{
BTNODE *new;
int i;
int m;
BTNODE *left;
int lkeys;
/* Test parameters */
if (((node->nkeys > 0) && (node->nkeys >= tree->order - 1)) ||
(n < 0))
{
return 0;
}
/* Create a new node */
new = (BTNODE*) bt_malloc(sizeof(BTNODE));
if (new != NULL)
{
new->parent = node;
/* Allocate new key array */
new->keys = (char**) bt_malloc(tree->order*sizeof(char*));
if (new->keys != NULL)
{
/* Calculate needed partial results */
m = tree->order / 2;
left = node->children[n];
lkeys = left->nkeys;
/* Allocate new child array */
if (left->children != NULL)
{
new->children =
(BTNODE**) bt_malloc((tree->order + 1) *
sizeof(BTNODE*));
if (new->children != NULL)
{
for (i = 0; i <= lkeys - m; i++)
{
new->children[i] =
left->children[m + i];
new->children[i]->parent = new;
}
}
else
{
bt_free(new->keys);
bt_free(new);
return 0;
}
}
else
{
new->children = NULL;
}
/* Split keys */
for (i = 0; i < lkeys - m; i++)
{
new->keys[i] = left->keys[m + i];
}
new->nkeys = lkeys - m;
left->nkeys = m - 1;
/* Elevate the key where the split was made */
for (i = node->nkeys; i > n; i--)
{
node->keys[i] = node->keys[i-1];
node->children[i+1] = node->children[i];
}
node->children[n+1] = new;
node->keys[n] = left->keys[m - 1];
node->nkeys++;
tree->capacity += tree->order - 1;
return 1;
}
/* Failed to allocate new child array, free node */
bt_free(new);
}
/* Failed to allocate new node, return FALSE */
return 0;
}
/*********************************************************************
*
* bt_rebalance -- This function tries to rebalance the two adjacent
* nodes. This is needed when an insertion is attempted
* into a node that is already full but its neighbors are
* not, or when a deletion is made and the node is less
* than half-full.
*
*********************************************************************/
static bt_rebalance(node,n,order)
BTNODE *node;
int n;
int order;
{
int res;
if (node->children[n]->nkeys < (order-1)/2)
{
res = bt_rotateLeft(node,n,order);
}
else
if ((n < node->nkeys) && (node->children[n+1]->nkeys < (order-1)/2))
{
res = bt_rotateRight(node,n,order);
}
return;
}
/*********************************************************************
*
* bt_insertNode -- This function performs a recursive-descent of a b-tree,
* inserting a new key in a leaf node. If the leaf is
* full, the tree is reorganized to make room. -1 is
* returned if the insert fails due to a duplicate key.
* 0 is returned if the insert fails for some other
* reason. 1 is returned if successful.
*
*********************************************************************/
static int bt_insertNode(tree,node,key)
BTREE tree;
BTNODE *node;
char *key;
{
int i;
int res;
/* Locate proper place for new key in node */
i = bt_searchNode(node,key,tree->comp,&res);
if (res) return -1;
/* If no children, insert key in this node */
if (node->children == NULL)
{
return bt_insertKey(node,key,i,tree->order);
}
/* Try to insert the new key in a child node */
res = bt_insertNode(tree,node->children[i],key);
/* Child is full, reorganize */
if (res == 0)
{
/* Try rotating right */
if ((res == 0) && (i < node->nkeys) &&
(node->children[i+1]->nkeys < tree->order - 2))
{
res = bt_rotateRight(node,i,tree->order);
}
/* Try rotating left */
if ((res == 0) && (i > 0) &&
(node->children[i-1]->nkeys < tree->order - 2))
{
res = bt_rotateLeft(node,i - 1,tree->order);
}
/* Can't rotate, try bursting */
if (res == 0) res = bt_burst(tree,node,i);
if (res > 0)
{
res = bt_insertNode(tree,node,key);
if (res > 0)
{
bt_rebalance(node,i,tree->order);
}
}
}
return res;
}
/*********************************************************************
*
* bt_insert -- This function inserts a new key into a b-tree. -1 is
* returned if the insert fails due to a duplicate key.
* 0 is returned if the insert fails for some other
* reason. 1 is returned if successful.
*
*********************************************************************/
int bt_insert(ptree,key)
char *ptree;
char *key;
{
int res;
BTNODE *new;
BTNODE *node;
BTREE tree;
tree = (BTREE) ptree;
/* Begin at root */
node = tree->root;
/* If root is empty, insert first key */
if (node->nkeys == 0)
{
node->keys[0] = key;
node->nkeys = 1;
tree->contains = 1;
tree->currNode = NULL;
return 1;
}
/* Try inserting new key */
res = bt_insertNode(tree,node,key);
/* If 0 return, burst the root, rebalance, and try again */
if (res == 0)
{
new = (BTNODE*) bt_malloc(sizeof(BTNODE));
if (new != NULL)
{
new->children = (BTNODE**) bt_malloc((tree->order + 1) *
sizeof(BTNODE*));
if (new->children != NULL)
{
new->keys = (char**) bt_malloc((tree->order) *
sizeof(char*));
if (new->keys != NULL)
{
new->nkeys = 0;
new->children[0] = node;
node->parent = new;
tree->root = new;
tree->capacity += tree->order - 1;
res = bt_burst(tree,new,0);
if (res > 0)
{
res=bt_insertNode(tree,new,key);
}
if (res > 0)
{
tree->contains++;
bt_rebalance(new,0,tree->order);
tree->currNode = NULL;
}
return res;
}
bt_free(new->children);
}
bt_free(new);
}
}
if (res > 0)
{
tree->contains++;
tree->currNode = NULL;
}
return res;
}
SHAR_EOF
fi
if test -f 'btmalloc.c'
then
echo shar: "will not over-write existing file 'btmalloc.c'"
else
cat << \SHAR_EOF > 'btmalloc.c'
/**************************************************************
*
* btmalloc.c -- This file contains functions that augment the
* C runtime library memory allocator in order
* to aid debugging.
*
**************************************************************/
#include <stdio.h>
/* The following structure is used for debugging heap corruptions */
struct heapblk {
char *blk;
int freeNext;
};
struct heap_struct {
int allocSeq;
int freeLast;
struct heapblk blks[10000];
};
struct heap_struct btheap = {0,-1};
/*
* The following code is used for allocating space on the heap. When not
* debugging heap corruptions, a macro aliases bt_malloc with malloc.
*/
char *bt_malloc(size)
unsigned size;
{
char *temp;
temp = (char*) malloc(size);
btheap.blks[btheap.allocSeq].blk = temp;
btheap.blks[btheap.allocSeq].freeNext = -2;
btheap.allocSeq++;
return temp;
}
/*
* The following code is used for freeing memory on the heap. If not
* debugging heap corruptions, bt_free is aliased with free.
*/
bt_free(ptr)
char *ptr;
{
int i;
printf("Freeing heap storage at %x\n",ptr);
for (i = 0; i < btheap.allocSeq; i++)
{
if (ptr == btheap.blks[i].blk)
{
if (btheap.blks[i].freeNext == -2)
{
btheap.blks[i].freeNext = btheap.freeLast;
btheap.freeLast = i;
free(ptr);
return;
}
else
{
printf(
"ERROR: freeing %x which was already freed\n",
ptr);
printf("Block\n");
i = btheap.freeLast;
while (i > 0)
{
printf("%x\n",btheap.blks[i].blk);
i = btheap.blks[i].freeNext;
}
fflush(stdout);
kill(getpid(),5);
}
}
}
printf("ERROR: Freeing %x which has not been allocated\n",ptr);
fflush(stdout);
kill(getpid(),5);
}
/* The following verifies the integrity of the heap. */
int bt_malloc_verify()
{
int retval;
int once;
int i;
retval = 1;
once = 0;
#ifdef DEBUG
for (i = 0; i < btheap.allocSeq; i++)
{
if (btheap.blks[i].freeNext == -2)
{
if (!once)
{
once = 1;
printf("The following blocks are allocated:\n");
}
printf("%x\n",btheap.blks[i].blk);
}
}
fflush(stdout);
#endif
#ifdef sun
retval = malloc_verify();
#endif
return retval;
}
SHAR_EOF
fi
if test -f 'btnew.c'
then
echo shar: "will not over-write existing file 'btnew.c'"
else
cat << \SHAR_EOF > 'btnew.c'
/***********************************************************************
*
* btnew.c -- This file contains functions to create a new in-memory
* B-tree.
*
***********************************************************************/
#include <stdio.h>
#include "btpriv.h"
/***********************************************************************
*
* bt_new -- Given the number of children each node is allowed to have,
* and a pointer to a strcmp-like function that compares two
* keys, this function creates an empty b-tree structure.
*
***********************************************************************/
char *bt_new(order,comp)
int order;
int (*comp)();
{
BTREE tree;
int i;
/* Validate parameters */
if ((comp == NULL) || (order < 3)) return (char *) NULL;
/* Allocate the handle */
tree = (BTREE) bt_malloc(sizeof(struct btree));
if (tree != NULL)
{
/* Allocate the root */
tree->root = (BTNODE*) bt_malloc(sizeof(struct btnode));
if (tree->root != NULL)
{
/* Initialize root */
tree->order = order;
tree->comp = comp;
tree->root->nkeys = 0;
tree->root->children = NULL;
/* Allocate key array */
tree->root->keys =
(char**)bt_malloc((order - 1) * sizeof(char*));
if (tree->root->keys != NULL)
{
/* Initialize keys */
for (i = 0; i < order - 1; i++)
{
tree->root->keys[i] = NULL;
}
tree->root->nkeys = 0;
tree->root->parent = NULL;
tree->contains = 0;
tree->capacity = order - 1;
tree->currNode = NULL;
return (char *) tree;
}
/* Failed to allocate keys, free tree */
bt_free(tree->root);
}
/* Failed to allocate root, free handle */
bt_free(tree);
}
/* Failed to allocate handle, return null (error) */
return (char *) NULL;
}
SHAR_EOF
fi
if test -f 'btsearch.c'
then
echo shar: "will not over-write existing file 'btsearch.c'"
else
cat << \SHAR_EOF > 'btsearch.c'
/********************************************************************
* btsearch -- This file contains functions needed to locate an
* item in an in-memory B-tree.
*
********************************************************************/
#include <stdio.h>
#include "btpriv.h"
/********************************************************************
*
* bt_searchNode -- This function searches a node for a key. If the key
* is found, its index in the node's key array is
* returned, along with a flag indicating that the key
* was found. If the key is not found, the index of the
* next higher key in the key array is returned, along
* with a "not found" indication.
*
********************************************************************/
static int bt_searchNode(node,target,comp,eq)
BTNODE *node; /* Node to be searched */
char *target; /* Key to search for */
int (*comp)(); /* strcmp()-like comparison function */
int *eq; /* 0 if not found, non-zero otherwise */
{
int i;
int res;
int hi;
int lo;
res = -1;
/*
* Perform linear search of node contains 7 keys or less,
* otherwise perform binary search
*/
if (node->nkeys <= 7)
{
for (i = 0; i < node->nkeys; i++)
{
res = (*comp)(node->keys[i],target);
if (res >= 0) break;
}
}
else
{
lo = 0;
hi = node->nkeys - 1;
while ((lo <= hi) && (res != 0))
{
i = (lo + hi) / 2;
res = (*comp)(node->keys[i],target);
if (res < 0) lo = i + 1;
else if (res > 0) hi = i - 1;
}
if (res < 0) i++;
}
*eq = (res == 0); /* Indicate successful search */
node->currKey = i + *eq - 1;
return i;
}
/***********************************************************************
*
* bt_locate -- This function performs a recursive-descent search of
* a sub-tree for a key. The key is returned if found,
* or NULL otherwise.
*
***********************************************************************/
static char *bt_locate(tree,node,target,comp)
BTREE tree;
BTNODE *node;
char *target;
int (*comp)();
{
int res;
int i;
int eq;
i = bt_searchNode(node,target,comp,&eq);
node->currKey = i;
if (eq)
{
tree->currNode = node;
tree->nextOk = 1;
return node->keys[i];
}
else if (node->children == NULL)
{
tree->currNode = node;
tree->nextOk = 0;
return NULL;
}
else
{
return bt_locate(tree,node->children[i],target,comp);
}
}
/***********************************************************************
*
* bt_search -- This function searches a tree for a specified key. The
* key is returned if found, or NULL if not.
*
***********************************************************************/
char *bt_search(tree,target)
BTREE tree;
char *target;
{
if (tree == NULL) return NULL;
return bt_locate(tree,tree->root,target,tree->comp);
}
SHAR_EOF
fi
if test -f 'bttraverse.c'
then
echo shar: "will not over-write existing file 'bttraverse.c'"
else
cat << \SHAR_EOF > 'bttraverse.c'
/****************************************************************
*
* bttraverse.c -- This file contains functions needed to
* traverse an in-memory B-tree, passing each
* item stored there to a callback function.
*
****************************************************************/
#include <stdio.h>
#include "btpriv.h"
/****************************************************************
*
* bt_visit -- This function is used while traversing a b-tree.
* It is called once for each node. It calls some
* specified function once for each key in its
* key array, and calls itself once for each child
* in its child array.
*
****************************************************************/
static void bt_visit(node,fn,parms)
BTNODE *node;
void (*fn)();
char *parms;
{
int i;
if (node == NULL) return;
for (i = 0; i < node->nkeys; i++)
{
if (node->children != NULL)
{
bt_visit(node->children[i],fn,parms);
}
(*fn)(node->keys[i],parms);
}
if (node->children != NULL)
{
bt_visit(node->children[i],fn,parms);
}
return;
}
/****************************************************************
*
* bt_traverse -- This function traverses a b-tree, calling some
* specified function once for each key stored in
* it. The specified function has the following
* protocol:
*
* fn(key,parms)
* char *key;
* char *parms;
*
* where key is a pointer to a key stored in the
* btree, and parms is the parameter structure
* passed by the caller.
*
* The nodes are visited in descending order, if
* the comp function passed to bt_new is
* strcmp-like.
*
****************************************************************/
void bt_traverse(ptree,fn,parms)
char *ptree;
void (*fn)();
char *parms;
{
BTREE tree;
tree = (BTREE) ptree;
bt_visit(tree->root,fn,parms);
return;
}
SHAR_EOF
fi
if test -f 'btutil.c'
then
echo shar: "will not over-write existing file 'btutil.c'"
else
cat << \SHAR_EOF > 'btutil.c'
/********************************************************************
*
* btutil.c -- This function contains utility functions that are
* used for many features of an in-memory B-tree
* implementation.
*
********************************************************************/
#define __BTUTIL_C__
#include <stdio.h>
#include "btpriv.h"
/********************************************************************
*
* bt_searchNode -- This function searches a node for a key. If the key
* is found, its index in the node's key array is
* returned, along with a flag indicating that the key
* was found. If the key is not found, the index of the
* next higher key in the key array is returned, along
* with a "not found" indication.
*
********************************************************************/
int bt_searchNode(node,target,comp,eq)
BTNODE *node; /* Node to be searched */
char *target; /* Key to search for */
int (*comp)(); /* strcmp()-like comparison function */
int *eq; /* 0 if not found, non-zero otherwise */
{
int i;
int res;
int hi;
int lo;
res = -1;
/*
* Perform linear search of node contains 7 keys or less,
* otherwise perform binary search
*/
if (node->nkeys <= 7)
{
for (i = 0; i < node->nkeys; i++)
{
res = (*comp)(node->keys[i],target);
if (res >= 0) break;
}
}
else
{
lo = 0;
hi = node->nkeys - 1;
while ((lo <= hi) && (res != 0))
{
i = (lo + hi) / 2;
res = (*comp)(node->keys[i],target);
if (res < 0) lo = i + 1;
else if (res > 0) hi = i - 1;
}
if (res < 0) i++;
}
*eq = (res == 0); /* Indicate successful search */
node->currKey = i + *eq - 1;
return i;
}
/******************************************************************
*
* bt_rotateRight -- Given a node and an index into its key array, this
* function rotates the node right at the specified
* key. This is used during insertion and deletion to
* keep the tree balanced. The return value is 0 if
* the function fails, i.e. the node on the left
* cannot lose keys, the node on the right cannot
* gain keys, or the specified node is a leaf; 1 is
* returned if successful.
*
******************************************************************/
int bt_rotateRight(node,n,order)
BTNODE *node;
int n;
int order;
{
int i;
BTNODE *right;
BTNODE *left;
/* Test parameters */
if ((n >= node->nkeys) || (n < 0))
{
return 0;
}
/* Point to children */
left = node->children[n];
right = node->children[n+1];
/* Return FALSE if rotation is not possible */
if ((left == NULL) ||
(left->nkeys <= order/2) ||
(right->nkeys >= order - 1))
{
return 0;
}
/* Shift the right child's keys */
for (i = right->nkeys; i > 0; i--)
{
right->keys[i] = right->keys[i - 1];
}
/* Rotate keys */
right->keys[0] = node->keys[n];
node->keys[n] = left->keys[left->nkeys - 1];
left->keys[left->nkeys - 1] = NULL;
if (right->children != NULL)
{
/* Shift the right child's children */
for (i = right->nkeys; i >= 0; i--)
{
right->children[i + 1] = right->children[i];
}
/* Rotate children */
right->children[0] = left->children[left->nkeys];
right->children[0]->parent = right;
left->children[left->nkeys] = NULL;
}
/* Update key count and return TRUE */
right->nkeys++;
left->nkeys--;
return 1;
}
/******************************************************************
*
* bt_rotateLeft -- Given a node and an index into its key array, this
* function rotates the node left at the specified
* key. This is used during insertion and deletion to
* keep the tree balanced. The return value is 0 if
* the function fails, i.e. the node on the right
* cannot lose keys, the node on the left cannot
* gain keys, or the specified node is a leaf; 1 is
* returned when successful.
*
******************************************************************/
int bt_rotateLeft(node,n,order)
BTNODE *node;
int n;
int order;
{
int i;
BTNODE *right;
BTNODE *left;
/* Test parameters */
if ((n < 0) || (n >= node->nkeys))
{
return 0;
}
/* Point to children */
right = node->children[n+1];
left = node->children[n];
/* Return FALSE if rotation is not possible */
if ((left == NULL) ||
(right->nkeys <= order/2) ||
(left->nkeys >= order - 1))
{
return 0;
}
/* Rotate keys */
left->keys[left->nkeys] = node->keys[n];
node->keys[n] = right->keys[0];
/* Update key counts */
left->nkeys ++;
right->nkeys --;
/* Shift the right child's keys */
for (i = 0; i < right->nkeys; i++)
{
right->keys[i] = right->keys[i+1];
}
right->keys[i] = NULL;
if (left->children != NULL)
{
/* Rotate children */
left->children[left->nkeys] = right->children[0];
left->children[left->nkeys]->parent = left;
/* Shift the right child's children */
for (i = 0; i <= right->nkeys; i++)
{
right->children[i] = right->children[i+1];
}
right->children[i+1] = NULL;
}
/* Return TRUE */
return 1;
}
SHAR_EOF
fi
if test -f 'test.c'
then
echo shar: "will not over-write existing file 'test.c'"
else
cat << \SHAR_EOF > 'test.c'
#include <stdio.h>
#include "btree.h"
/* #define DEBUGGING */
#define LOOPS 500
#define ORDER 12
typedef struct key {
int key;
} KEY;
KEY savedKeys[LOOPS];
dump(key)
KEY *key;
{
if (key == NULL) printf("********NULL**********\n");
else printf("%x: %d\n",key,key->key);
}
visit(key,parms)
KEY *key;
char *parms;
{
dump(key);
}
comp(k1,k2)
KEY *k1,*k2;
{
return (k1->key - k2->key);
}
main()
{
BTREE tree;
KEY *key;
int i;
int res;
KEY *key1;
KEY *key2;
KEY *key3;
KEY *key4;
KEY tkey;
#ifdef DEBUGGING
#ifdef sun
malloc_debug(2);
#endif
#endif
tree = (BTREE)bt_new(ORDER,comp);
if (tree == NULL)
{
printf("Failed to create tree\n");
exit(1);
}
(void) bt_malloc_verify();
for (i = 0; i < LOOPS; i++)
{
printf("Iteration %d\n",i+1);
key = &savedKeys[i];
key->key = rand();
printf("Inserting %d\n",key->key);
fflush(stdout);
res = bt_insert(tree,key);
if (res > 0)
{
printf("Inserted %d\n",key->key);
}
else if (res < 0)
{
printf("Duplicate key %d\n",key->key);
}
else
{
printf("Error inserting key %d\n");
exit(3);
}
printf("Trying duplicate\n");
res = bt_insert(tree,key);
if (res < 0)
{
printf("Failed to insert duplicate\n");
}
else if (res == 0)
{
printf("Error inserting duplicate\n");
exit(4);
}
else
{
printf("Succeeded in inserting duplicate\n");
exit(5);
}
#if 0
#ifdef DEBUGGING
printf("Contents of tree:\n");
bt_dump(tree,dump);
#endif
#endif 0
}
printf("Finished creating the tree.\n");
printf("Contents of tree follow:\n");
bt_traverse(tree,visit,NULL);
for (i = 0; i < LOOPS; i++)
{
printf("Iteration %d\n",i);
printf("Seeking %d at %x\n",savedKeys[i].key,&savedKeys[i]);
key = (KEY*)bt_search(tree,&savedKeys[i]);
if (key != &savedKeys[i])
{
printf("Can't find %d, returned %x\n",savedKeys[i].key,
key);
}
printf("Freeing %d at %x\n",savedKeys[i].key,&savedKeys[i]);
fflush(stdout);
key = (KEY*)bt_delete(tree,&savedKeys[i]);
if (key != &savedKeys[i])
{
printf("Problem freeing %d at %x, returned %x\n",
savedKeys[i].key,&savedKeys[i].key,key);
}
else
{
printf("Freed %d, returned %x\n",savedKeys[i].key,key);
}
#ifdef DEBUGGING
printf("Contents of tree:\n");
bt_dump(tree,dump);
fflush(stdout);
#endif
key = (KEY*)bt_search(tree,&savedKeys[i]);
if (key == &savedKeys[i])
{
printf("Found %d after deletion\n",savedKeys[i].key);
}
key = (KEY*)bt_delete(tree,&savedKeys[i]);
if (key != NULL)
{
printf("%d remained in tree after deletion at %x\n",
savedKeys[i].key,key);
}
#if 0
#ifdef DEBUGGING
printf("Contents of tree:\n");
bt_dump(tree,dump);
#endif
#endif 0
}
(void) bt_malloc_verify();
printf("Freeing tree\n");
bt_destroy(tree,NULL);
printf("Finished freeing tree\n");
printf("Malloc verify: ");
if (bt_malloc_verify())
{
printf("success\n");
fflush(stdout);
}
else
{
printf("failure\n");
fflush(stdout);
exit(6);
}
printf("Creating second tree\n");
tree = (BTREE)bt_new(ORDER,comp);
if (tree == NULL)
{
printf("Failed to create tree\n");
exit(7);
}
(void) bt_malloc_verify();
printf("Contents of tree:\n");
bt_dump(tree,dump);
for (i = 0; i < LOOPS; i++)
{
printf("Iteration %d\n",i+1);
key = &savedKeys[i];
key->key = rand();
printf("Inserting %d\n",key->key);
fflush(stdout);
res = bt_insert(tree,key);
if (res > 0)
{
printf("Inserted %d\n",key->key);
}
else if (res < 0)
{
printf("Duplicate key %d\n",key->key);
}
else
{
printf("Error inserting key %d\n");
exit(8);
}
#if 0
#ifdef DEBUGGING
printf("Contents of tree:\n");
bt_dump(tree,dump);
#endif
#endif 0
}
printf("Finished creating the tree.\n");
printf("Contents of tree follow:\n");
bt_traverse(tree,visit,NULL);
printf("Contents of tree:\n");
bt_dump(tree,dump);
printf("Testing first and next\n");
key = (KEY *) bt_first(tree);
while (key != NULL)
{
dump(key);
key = (KEY *) bt_next(tree);
}
printf("Backing up\n");
key = (KEY *) bt_prev(tree);
dump(key);
printf("Testing last and prev\n");
key = (KEY *) bt_last(tree);
while (key != NULL)
{
dump(key);
key = (KEY *) bt_prev(tree);
}
printf("Stepping forward\n");
key = (KEY *) bt_next(tree);
dump(key);
printf("Testing search\n");
key1 = (KEY *) bt_first(tree);
key2 = (KEY *) bt_next(tree);
key4 = (KEY *) bt_last(tree);
key3 = (KEY *) bt_prev(tree);
dump(key1);
dump(key2);
dump(key3);
dump(key4);
printf("Testing search at beginning\n");
key = (KEY *) bt_search(tree,key1);
if (key == key1)
{
printf("Successful search okay\n");
key = (KEY *) bt_next(tree);
if (key == key2) printf("next okay\n");
else
{
printf("next bad\n");
dump(key);
}
key = (KEY *) bt_search(tree,key1);
key = (KEY *) bt_prev(tree);
if (key == NULL) printf("prev Ok\n");
else
{
printf("prev bad\n");
dump(key);
}
}
else
{
printf("Successful search failed\n");
}
printf("Testing search at end\n");
key = (KEY *) bt_search(tree,key4);
if (key == key4)
{
printf("Successful search okay\n");
key = (KEY *) bt_prev(tree);
if (key == key3) printf("prev okay\n");
else
{
printf("prev bad\n");
dump(key);
}
key = (KEY *) bt_search(tree,key4);
key = (KEY *) bt_next(tree);
if (key == NULL) printf("next Ok\n");
else
{
printf("next bad\n");
dump(key);
}
}
else
{
printf("Successful search failed\n");
}
printf("Testing first unsuccessful key\n");
tkey.key = key1->key + 1;
key = (KEY *) bt_search(tree,&tkey);
if (key == NULL)
{
printf("Unsuccessful search okay\n");
key = (KEY *) bt_next(tree);
if (key == key2) printf("next ok\n");
else
{
printf("next bad\n");
dump(key);
}
key = (KEY *) bt_search(tree,&tkey);
key = (KEY *) bt_prev(tree);
if (key == key1) printf("prev ok\n");
else
{
printf("prev bad\n");
dump(key);
}
}
else
{
printf("Unsuccessful search failed\n");
}
printf("Testing second unsuccessful key\n");
tkey.key = key4->key - 1;
key = (KEY *) bt_search(tree,&tkey);
if (key == NULL)
{
printf("Unsuccessful search okay\n");
key = (KEY *) bt_next(tree);
if (key == key4) printf("next ok\n");
else
{
printf("next bad\n");
dump(key);
}
key = (KEY *) bt_search(tree,&tkey);
key = (KEY *) bt_prev(tree);
if (key == key3) printf("prev ok\n");
else
{
printf("prev bad\n");
dump(key);
}
}
else
{
printf("Unsuccessful search failed\n");
}
printf("Testing third unsuccessful key\n");
tkey.key = key1->key - 1;
key = (KEY *) bt_search(tree,&tkey);
if (key == NULL)
{
printf("Unsuccessful search okay\n");
key = (KEY *) bt_next(tree);
if (key == key1) printf("next ok\n");
else
{
printf("next bad\n");
dump(key);
}
key = (KEY *) bt_search(tree,&tkey);
key = (KEY *) bt_prev(tree);
if (key == NULL) printf("prev ok\n");
else
{
printf("prev bad\n");
dump(key);
}
}
else
{
printf("Unsuccessful search failed\n");
}
printf("Testing fourth unsuccessful key\n");
tkey.key = key4->key + 1;
key = (KEY *) bt_search(tree,&tkey);
if (key == NULL)
{
printf("Unsuccessful search okay\n");
key = (KEY *) bt_next(tree);
if (key == NULL) printf("next ok\n");
else
{
printf("next bad\n");
dump(key);
}
key = (KEY *) bt_search(tree,&tkey);
key = (KEY *) bt_prev(tree);
if (key == key4) printf("prev ok\n");
else
{
printf("prev bad\n");
dump(key);
}
}
else
{
printf("Unsuccessful search failed\n");
}
printf("Freeing 3/4 of the keys\n");
for (i = 0; i < 3 * LOOPS / 4; i++)
{
printf("Iteration %d\n",i+1);
key = &savedKeys[i];
key1 = (KEY*) bt_delete(tree,key);
if (key1 == key) printf("Deletion okay\n");
else printf("Deletion error, wanted %x, got %x\n",key,key1);
fflush(stdout);
#if 0
#ifdef DEBUGGING
printf("Contents of tree:\n");
bt_dump(tree,dump);
#endif
#endif 0
}
printf("Finished deleting keys.\n");
printf("Contents of tree follow:\n");
bt_traverse(tree,visit,NULL);
printf("Contents of tree:\n");
bt_dump(tree,dump);
printf("Testing first and next\n");
key = (KEY *) bt_first(tree);
while (key != NULL)
{
dump(key);
key = (KEY *) bt_next(tree);
}
printf("Backing up\n");
key = (KEY *) bt_prev(tree);
dump(key);
printf("Testing last and prev\n");
key = (KEY *) bt_last(tree);
while (key != NULL)
{
dump(key);
key = (KEY *) bt_prev(tree);
}
printf("Stepping forward\n");
key = (KEY *) bt_next(tree);
dump(key);
printf("Testing search\n");
key1 = (KEY *) bt_first(tree);
key2 = (KEY *) bt_next(tree);
key4 = (KEY *) bt_last(tree);
key3 = (KEY *) bt_prev(tree);
dump(key1);
dump(key2);
dump(key3);
dump(key4);
printf("Testing search at beginning\n");
key = (KEY *) bt_search(tree,key1);
if (key == key1)
{
printf("Successful search okay\n");
key = (KEY *) bt_next(tree);
if (key == key2) printf("next okay\n");
else
{
printf("next bad\n");
dump(key);
}
key = (KEY *) bt_search(tree,key1);
key = (KEY *) bt_prev(tree);
if (key == NULL) printf("prev Ok\n");
else
{
printf("prev bad\n");
dump(key);
}
}
else
{
printf("Successful search failed\n");
}
printf("Testing search at end\n");
key = (KEY *) bt_search(tree,key4);
if (key == key4)
{
printf("Successful search okay\n");
key = (KEY *) bt_prev(tree);
if (key == key3) printf("prev okay\n");
else
{
printf("prev bad\n");
dump(key);
}
key = (KEY *) bt_search(tree,key4);
key = (KEY *) bt_next(tree);
if (key == NULL) printf("next Ok\n");
else
{
printf("next bad\n");
dump(key);
}
}
else
{
printf("Successful search failed\n");
}
printf("Testing first unsuccessful key\n");
tkey.key = key1->key + 1;
key = (KEY *) bt_search(tree,&tkey);
if (key == NULL)
{
printf("Unsuccessful search okay\n");
key = (KEY *) bt_next(tree);
if (key == key2) printf("next ok\n");
else
{
printf("next bad\n");
dump(key);
}
key = (KEY *) bt_search(tree,&tkey);
key = (KEY *) bt_prev(tree);
if (key == key1) printf("prev ok\n");
else
{
printf("prev bad\n");
dump(key);
}
}
else
{
printf("Unsuccessful search failed\n");
}
printf("Testing second unsuccessful key\n");
tkey.key = key4->key - 1;
key = (KEY *) bt_search(tree,&tkey);
if (key == NULL)
{
printf("Unsuccessful search okay\n");
key = (KEY *) bt_next(tree);
if (key == key4) printf("next ok\n");
else
{
printf("next bad\n");
dump(key);
}
key = (KEY *) bt_search(tree,&tkey);
key = (KEY *) bt_prev(tree);
if (key == key3) printf("prev ok\n");
else
{
printf("prev bad\n");
dump(key);
}
}
else
{
printf("Unsuccessful search failed\n");
}
printf("Testing third unsuccessful key\n");
tkey.key = key1->key - 1;
key = (KEY *) bt_search(tree,&tkey);
if (key == NULL)
{
printf("Unsuccessful search okay\n");
key = (KEY *) bt_next(tree);
if (key == key1) printf("next ok\n");
else
{
printf("next bad\n");
dump(key);
}
key = (KEY *) bt_search(tree,&tkey);
key = (KEY *) bt_prev(tree);
if (key == NULL) printf("prev ok\n");
else
{
printf("prev bad\n");
dump(key);
}
}
else
{
printf("Unsuccessful search failed\n");
}
printf("Testing fourth unsuccessful key\n");
tkey.key = key4->key + 1;
key = (KEY *) bt_search(tree,&tkey);
if (key == NULL)
{
printf("Unsuccessful search okay\n");
key = (KEY *) bt_next(tree);
if (key == NULL) printf("next ok\n");
else
{
printf("next bad\n");
dump(key);
}
key = (KEY *) bt_search(tree,&tkey);
key = (KEY *) bt_prev(tree);
if (key == key4) printf("prev ok\n");
else
{
printf("prev bad\n");
dump(key);
}
}
else
{
printf("Unsuccessful search failed\n");
}
printf("Freeing tree\n");
bt_destroy(tree,NULL);
printf("Finished freeing tree\n");
printf("Malloc verify: ");
if (bt_malloc_verify()) printf("success\n");
else printf("failure\n");
fflush(stdout);
exit(0);
}
SHAR_EOF
fi
exit 0
# End of shell archive
--
Paul Sander (408) 734-9822 | "Passwords are like underwear," she said,
paul@Atherton.COM | "Both should be changed often."
{decwrl,pyramid,sun}!athertn!paul | -- Bennett Falk in "Mom Meets Unix"
Technical Details
Message-ID:
<28983@athertn.Atherton.COM>Path:
arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!wuarchive!decwrl!nsc!pyramid!athertn!paulReferences:
<27705@athertn.Atherton.COM> <533@helios.prosys.se> <27914@athertn.Atherton.COM> <28982@athertn.Atherton.COM>Show Full Headers
Complete Article Headers
Path: arc1-ca.pugleaf.net!utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!wuarchive!decwrl!nsc!pyramid!athertn!paul From: paul@athertn.Atherton.COM (Paul Sander) Newsgroups: comp.sw.components Subject: Re: What is a reusable software component? Message-ID: <28983@athertn.Atherton.COM> Date: 18 Aug 90 04:38:41 GMT References: <27705@athertn.Atherton.COM> <533@helios.prosys.se> <27914@athertn.Atherton.COM> <28982@athertn.Atherton.COM> Reply-To: paul@Atherton.COM (Paul Sander) Organization: Atherton Technology, Sunnyvale, CA Lines: 2386