mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
358 lines
11 KiB
358 lines
11 KiB
#include <stdio.h>
|
|
#include <malloc.h>
|
|
#include "dict0.h"
|
|
|
|
/************************************************************************/
|
|
TreeNode Dumbo;
|
|
// volatile
|
|
TreeNode *Dummy = &Dumbo; // a global dummy node
|
|
|
|
#define ROTATELEFT tmp=t->right; t->right=tmp->left; tmp->left=t; t=tmp
|
|
#define ROTATERIGHT tmp=t->left; t->left=tmp->right; tmp->right=t; t=tmp
|
|
#define LINKLEFT tmp=t; t=t->right; l=l->right=tmp
|
|
#define LINKRIGHT tmp=t; t=t->left; r=r->left=tmp
|
|
#define ASSEMBLE r->left=t->right; l->right=t->left; \
|
|
t->left=Dummy->right; t->right=Dummy->left
|
|
/************************************************************************/
|
|
|
|
/************************************************************************
|
|
Basic structure declarations from dict0.h:
|
|
|
|
typedef struct tnode {
|
|
struct tnode *left; // left child pointer
|
|
struct tnode *right; // right child pointer
|
|
void *item; // pointer to some structure
|
|
} TreeNode;
|
|
|
|
typedef struct dictnode {
|
|
TreeNode *root; // pointer to the root of a SAT
|
|
long size; // number of records in dictionary
|
|
void * state; // reserved for state info
|
|
// int (*cmp_rec)(void *, void *); comparison function pointer
|
|
cmp_rec_func cmp_rec;
|
|
TreeNode* (*splay)(TreeNode *, void *, cmp_rec_func);
|
|
// pointer to a splay function
|
|
void (*print_rec)(void *); // one line print function
|
|
} Dictionary;
|
|
|
|
#define DICT_CURR_ITEM(pDict) pDict->root->item
|
|
|
|
typedef enum {
|
|
SUCCESS,
|
|
ITEM_ALREADY_PRESENT,
|
|
ITEM_NOT_FOUND,
|
|
FIRST_ITEM,
|
|
LAST_ITEM,
|
|
EMPTY_DICTIONARY,
|
|
NULL_ITEM
|
|
}
|
|
Dict_Status;
|
|
**************************************************************************/
|
|
|
|
|
|
/*************************************************************************/
|
|
/*** MIDL_user_allocate / MIDL_user_free ***/
|
|
/*************************************************************************/
|
|
|
|
void *
|
|
MIDL_user_allocate(unsigned int count);
|
|
|
|
void
|
|
MIDL_user_free(void * p);
|
|
|
|
/*************************************************************************/
|
|
/*** Minimal Dictionary Operations: ***/
|
|
/*** ***/
|
|
/*** Dictionary *Dict_New(Cmp_rec*, Splay*, print_rec*) ***/
|
|
/*** ***/
|
|
/*** Dict_Status Dict_Find(Dictionary*, Item*) ***/
|
|
/*** Dict_Status Dict_Next(Dictionary*, Item*) ***/
|
|
/*** Dict_Status Dict_Prev(Dictionary*, Item*) ***/
|
|
/*** Dict_Status Dict_Insert(Dictionary*, Item*) ***/
|
|
/*** Dict_Status Dict_Delete(Dictionary*, Item**) ***/
|
|
/*** ***/
|
|
/*** Item* DICT_CURR_ITEM(Dict*) ***/
|
|
/*************************************************************************/
|
|
|
|
#define TreeNode_New(pnode, pitem) pnode = \
|
|
(TreeNode*) MIDL_user_allocate (sizeof(TreeNode)); \
|
|
pnode->left = pnode->right = NULL; pnode->item = pitem;
|
|
|
|
Dictionary*
|
|
Dict_New( // returns a new dictionary node
|
|
int (*cmp_rec) // pointer to item comparison function
|
|
(void *, void *),
|
|
TreeNode* (*splay) // pointer to a splay function
|
|
(TreeNode *, void *, cmp_rec_func),
|
|
void (*print_rec) // pointer to one line item print routine
|
|
(void *) )
|
|
{
|
|
Dictionary* dp;
|
|
dp = (Dictionary*)MIDL_user_allocate(sizeof(Dictionary));
|
|
dp->root = NULL;
|
|
dp->size = 0;
|
|
dp->state = NULL;
|
|
dp->print_rec = print_rec;
|
|
dp->splay = splay;
|
|
dp->cmp_rec = cmp_rec;
|
|
return(dp);
|
|
}
|
|
|
|
|
|
Dict_Status
|
|
Dict_Find(
|
|
Dictionary* dp, // Dictionary to be searched.
|
|
void* item) // Item searched for.
|
|
{
|
|
int keycmp;
|
|
TreeNode* t;
|
|
|
|
if (dp->root == NULL) return (EMPTY_DICTIONARY);
|
|
if (item == NULL) return(NULL_ITEM);
|
|
t = dp->root = dp->splay(dp->root, item, dp->cmp_rec);
|
|
keycmp = (dp->cmp_rec)( t->item, item );
|
|
if (keycmp != 0)
|
|
return(ITEM_NOT_FOUND);
|
|
else return(SUCCESS);
|
|
}
|
|
|
|
Dict_Status
|
|
Dict_Next(
|
|
Dictionary* dp, // Dictionary to be searched.
|
|
void* item) // A Key item. Advance to successor of item in dp.
|
|
{
|
|
TreeNode* t, *r;
|
|
int keycmp;
|
|
|
|
if (dp->root == NULL) return (EMPTY_DICTIONARY);
|
|
if (item == NULL) { dp->root = tdSplayLeft(dp->root);
|
|
return(SUCCESS);
|
|
}
|
|
if (item == DICT_CURR_ITEM(dp)) {
|
|
t = dp->root;
|
|
keycmp = 0; }
|
|
else {
|
|
dp->root = t = dp->splay(dp->root, item, dp->cmp_rec);
|
|
keycmp = (dp->cmp_rec)( item, t->item );
|
|
}
|
|
if (keycmp < 0)
|
|
return(SUCCESS);
|
|
else if (t->right == NULL) {
|
|
return(LAST_ITEM); }
|
|
else {
|
|
t = dp->root;
|
|
dp->root = tdSplayLeft(t->right);
|
|
dp->root->left = t;
|
|
t->right = NULL;
|
|
return(SUCCESS);
|
|
}
|
|
}
|
|
|
|
Dict_Status
|
|
Dict_Prev(
|
|
Dictionary* dp, // Dictionary to be searched.
|
|
void* item) // A Key item. Retreat to predecessor of item in dp.
|
|
{
|
|
TreeNode* t, s;
|
|
int keycmp;
|
|
|
|
if (dp->root == NULL) return (EMPTY_DICTIONARY);
|
|
if (item == NULL) { dp->root = tdSplayRight(dp->root);
|
|
return(SUCCESS);
|
|
}
|
|
if (item == DICT_CURR_ITEM(dp)) {
|
|
t = dp->root;
|
|
keycmp = 0; }
|
|
else {
|
|
dp->root = t = dp->splay(dp->root, item, dp->cmp_rec);
|
|
keycmp = (dp->cmp_rec)( item, t->item );
|
|
}
|
|
if (keycmp > 0)
|
|
return(SUCCESS);
|
|
else if (t->left == NULL) {
|
|
return(FIRST_ITEM); }
|
|
else {
|
|
t = dp->root;
|
|
dp->root = tdSplayRight(t->left);
|
|
dp->root->right = t;
|
|
t->left = NULL;
|
|
return(SUCCESS);
|
|
}
|
|
}
|
|
|
|
Dict_Status
|
|
Dict_Insert( // insert the given item into the tree
|
|
Dictionary* dp, // the modified dictionary
|
|
void* item) // the item to be inserted
|
|
{
|
|
int keycmp;
|
|
TreeNode *t, *newNode;
|
|
|
|
if (item == NULL) return(NULL_ITEM);
|
|
if (dp->root == NULL) {
|
|
TreeNode_New(newNode, item);
|
|
dp->root = newNode;
|
|
dp->size++;
|
|
return(SUCCESS);
|
|
}
|
|
t = dp->root = dp->splay(dp->root, item, dp->cmp_rec);
|
|
keycmp = (dp->cmp_rec)( t->item, item );
|
|
if (keycmp == 0)
|
|
return(ITEM_ALREADY_PRESENT);
|
|
|
|
TreeNode_New(newNode, item);
|
|
if (keycmp < 0) { // t->item < item
|
|
newNode->right = t->right;
|
|
t->right = NULL;
|
|
newNode->left = t; }
|
|
else {
|
|
newNode->left = t->left;
|
|
t->left = NULL;
|
|
newNode->right = t;
|
|
}
|
|
dp->root = newNode;
|
|
dp->size++;
|
|
return(SUCCESS);
|
|
}
|
|
|
|
|
|
Dict_Status
|
|
Dict_Delete( // delete the given item into from the tree
|
|
Dictionary* dp, // the modified dictionary
|
|
void** pItem) // IN: points to the (key) item to be deleted
|
|
// OUT: points to the item just deleted
|
|
{
|
|
TreeNode *t, *r;
|
|
int keycmp;
|
|
void* item = *pItem;
|
|
t = dp->root;
|
|
|
|
if (item == NULL) return(NULL_ITEM);
|
|
if (dp->root == NULL) return (EMPTY_DICTIONARY);
|
|
if (item == DICT_CURR_ITEM(dp))
|
|
keycmp = 0;
|
|
else {
|
|
dp->root = t = dp->splay(dp->root, item, dp->cmp_rec);
|
|
keycmp = (dp->cmp_rec)( item, t->item );
|
|
}
|
|
if (keycmp != 0)
|
|
return(ITEM_NOT_FOUND);
|
|
*pItem = DICT_CURR_ITEM(dp);
|
|
|
|
if (t->left == NULL) {
|
|
dp->root = t->right; }
|
|
else if ( (r = t->right) == NULL) {
|
|
dp->root = t->left; }
|
|
else {
|
|
r = tdSplayLeft(r);
|
|
// at this point r->left == NULL
|
|
r->left = t->left;
|
|
dp->root = r;
|
|
}
|
|
t->left = t->right = t->item = NULL;
|
|
MIDL_user_free(t);
|
|
dp->size--;
|
|
return(SUCCESS);
|
|
}
|
|
|
|
|
|
/*************************************************************************/
|
|
/***** Core functions (internal) *****/
|
|
/*************************************************************************/
|
|
|
|
TreeNode * // returns the new root
|
|
tdSplay( // general top down splay
|
|
TreeNode *root, // the current root of the tree
|
|
void *keyItem, // pointer to a "key item" searched for
|
|
int (*cmp)(void *, void *) )
|
|
// pointer to a comparison function
|
|
{
|
|
TreeNode* t=root; // current search point
|
|
TreeNode* l; // root of "left subtree" < keyItem
|
|
TreeNode* r; // root of "right subtree" > keyItem
|
|
int kcmpt, kcmpleft, kcmpright;
|
|
// cash comparison results
|
|
TreeNode* tmp;
|
|
|
|
/***/
|
|
Dummy = &Dumbo;
|
|
l = Dummy;
|
|
r = Dummy;
|
|
/***/
|
|
|
|
if ( (root == NULL) || ((*cmp)(keyItem, root->item) == 0) ) return (root);
|
|
Dummy->left=Dummy->right=NULL;
|
|
while ( (kcmpt = (*cmp)(keyItem, t->item)) != 0 ) {
|
|
if ( kcmpt < 0 ) {
|
|
if ( t->left == NULL ) break;
|
|
if ( (kcmpleft = (*cmp)(keyItem, t->left->item)) == 0 ) {
|
|
LINKRIGHT; }
|
|
else if ( kcmpleft < 0 ) {
|
|
ROTATERIGHT;
|
|
if ( t->left != NULL ) {
|
|
LINKRIGHT; } }
|
|
else { // keyItem > t->left->item
|
|
LINKRIGHT;
|
|
if ( t->right != NULL ) {
|
|
LINKLEFT; } } }
|
|
else { // keyItem > t->item
|
|
if ( t->right == NULL ) break;
|
|
if ( (kcmpright = (*cmp)(keyItem, t->right->item)) == 0 ) {
|
|
LINKLEFT; }
|
|
else if ( kcmpright > 0 ) {
|
|
ROTATELEFT;
|
|
if ( t->right != NULL ) {
|
|
LINKLEFT; } }
|
|
else { // keyItem < t->right->item
|
|
LINKLEFT;
|
|
if ( t->left != NULL ) {
|
|
LINKRIGHT; } }
|
|
}
|
|
}
|
|
// assemble:
|
|
r->left=t->right; l->right=t->left;
|
|
t->left=Dummy->right; t->right=Dummy->left;
|
|
return(t);
|
|
}
|
|
|
|
TreeNode*
|
|
tdSplayLeft(TreeNode* root)
|
|
{
|
|
TreeNode* t=root; // current "search" point
|
|
TreeNode* l=Dummy; // root of "left subtree" < keyItem
|
|
TreeNode* r=Dummy; // root of "right subtree" > keyItem
|
|
TreeNode* tmp;
|
|
|
|
if ((t == NULL) || (t->left == NULL)) return(t);
|
|
if (t->left->left == NULL) {
|
|
ROTATERIGHT; return(t); }
|
|
Dummy->left=Dummy->right=NULL;
|
|
while ( t->left != NULL ) {
|
|
ROTATERIGHT;
|
|
if ( t->left != NULL ) {
|
|
LINKRIGHT; }
|
|
}
|
|
r->left=t->right; l->right=t->left;
|
|
t->left=Dummy->right; t->right=Dummy->left;
|
|
return(t);
|
|
}
|
|
|
|
TreeNode*
|
|
tdSplayRight(TreeNode* root)
|
|
{
|
|
TreeNode* t=root; // current "search" point
|
|
TreeNode* l=Dummy; // root of "left subtree" < keyItem
|
|
TreeNode* r=Dummy; // root of "right subtree" > keyItem
|
|
TreeNode* tmp;
|
|
|
|
if ((t == NULL) || (t->right == NULL)) return(t);
|
|
Dummy->left=Dummy->right=NULL;
|
|
while ( t->right != NULL ) {
|
|
ROTATELEFT;
|
|
if ( t->right != NULL ) {
|
|
LINKLEFT; }
|
|
}
|
|
r->left=t->right; l->right=t->left;
|
|
t->left=Dummy->right; t->right=Dummy->left;
|
|
return(t);
|
|
}
|