建立接口
/*tree.h -- 二叉查找树*/
#pragma once //只编译一次
#define SLEN 20
/*根据具体情况定义Item*/
typedef struct item
{
char petname[SLEN];
char petkind[SLEN];
}Item;
#define MAXITEMS 10
typedef struct trnode
{
Item item;
struct trnode *left;
struct trnode *right;
}Trnode;
typedef struct tree
{
Trnode *root;
int size;
}Tree;
void InitializeTree(Tree *ptree); //初始化
bool TreeIsEmpty(const Tree *ptree); //判断是否为空
bool TreeIsFull(const Tree *ptree); //判断是否已满
int TreeItemCount(const Tree *ptree); //返回树的项数
bool AddItem(const Item *pi, Tree *ptree); //添加项
bool InTree(const Item *pi, const Tree *ptree); //查找
bool DeleteItem(const Item *pi, Tree *ptree); //删除项
/*把函数应用于树中的每一项(遍历树)*/
void Traverse(const Tree *ptree, void(*pfun)(Item item));
void DeleteAll(Tree *ptree); //清空树
实现接口
/*function.cpp,实现接口*/
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include"tree.h"
/*局部数据类型*/
typedef struct pair { /*包含两个指向树节点的指针*/
Trnode *child; /*用于SeekItem()函数*/
Trnode *parent;
}Pair;
/
/*局部函数的原型*/
static Trnode *MakeNode(const Item *pi);
static bool ToLeft(const Item *i1, const Item *i2);
static bool ToRight(const Item *i1, const Item *i2);
static void AddNode(Trnode *new_node, Trnode *root);
static void DeleteNode(Trnode **ptr);
static Pair SeekItem(const Item *pi, const Tree *ptree);
static void InOrder(const Trnode *root, void(*pfun)(Item item));
static void DeleteAllNodes(Trnode *root);
//
/*为新节点分配内存 MakeNode()函数*/
static Trnode * MakeNode(const Item *pi)
{
Trnode *new_node;
new_node = (Trnode *)malloc(sizeof(Trnode));
if (new_node != NULL)
{
new_node->item = *pi;
new_node->left = NULL;
new_node->right = NULL;
}
return new_node;
}
/*添加节点到非空树中 AddNode()函数*/
static bool ToLeft(const Item *i1, const Item *i2)
{
int comp1;
if ((comp1 = strcmp(i1->petname, i2->petname)) < 0)
return true;
else if (comp1 == 0 && strcmp(i1->petkind, i2->petkind) < 0)
return true;
else
return false;
}
static bool ToRight(const Item *i1, const Item *i2)
{
int comp1;
if ((comp1 = strcmp(i1->petname, i2->petname)) > 0)
return true;
else if (comp1 == 0 && strcmp(i1->petkind, i2->petkind) > 0)
return true;
else
return false;
}
static void AddNode(Trnode *new_node, Trnode *root)
{
if (ToLeft(&new_node->item, &root->item))
{
if (root->left == NULL)
root->left = new_node;
else
AddNode(new_node, root->left);
}
else if (ToRight(&new_node->item, &root->item))
{
if (root->right == NULL)
root->right = new_node;
else
AddNode(new_node, root->right);
}
else
{
fprintf(stderr, "location error in AddNode()\n");
exit(1);
}
}
/*查找项 SeekItem()函数*/
static Pair SeekItem(const Item *pi, const Tree *ptree)
{
Pair look;
look.parent = NULL;
look.child = ptree->root;
if (look.child == NULL)
return look; //提前退出
while (look.child != NULL)
{
if (ToLeft(pi, &(look.child->item)))
{
look.parent = look.child;
look.child = look.child->left;
}
else if (ToRight(pi, &(look.child->item)))
{
look.parent = look.child;
look.child = look.child->right;
}
else //如果两种情况都不满足,则必定相等
break; //look,child目标项的节点
}
return look;
}
/*删除一个节点,用于DeleteItem()*/
static void DeleteNode(Trnode **ptr)
/*ptr是指向目标节点的父节点指针成员的地址*/
{
Trnode *temp;
if ((*ptr)->left == NULL)
{
temp = *ptr;
*ptr = (*ptr)->right;
free(temp);
}
else if ((*ptr)->right == NULL)
{
temp = *ptr;
*ptr = (*ptr)->left;
free(temp);
}
else /*被删除的节点有两个子节点*/
{
/*找到重新连接右子树的位置*/
for (temp = (*ptr)->left; temp->right != NULL; temp = temp->right)
continue;
temp->right = (*ptr)->right;
temp = *ptr;
*ptr = (*ptr)->left;
free(temp);
}
}
/*InOrder()用于Traverse()*/
static void InOrder(const Trnode *root, void(*pfun)(Item item))
{
if (root != NULL)
{
InOrder(root->left, pfun);
(*pfun)(root->item);
InOrder(root->right, pfun);
}
}
/*DeleteAllNodes()用于DeleteAll()*/
static void DeleteAllNodes(Trnode *root) //主要作用为释放内存
{
Trnode *pright;
if (root != NULL)
{
pright = root->right;
DeleteAllNodes(root->left);
free(root);
DeleteAllNodes(pright);
}
}
//-------------------------------------------------------------------------------
/*$初始化*/
void InitializeTree(Tree *ptree)
{
ptree->root = NULL;
ptree->size = 0;
}
/*$判断树是否为空*/
bool TreeIsEmpty(const Tree *ptree)
{
if (ptree->root == NULL)
return true;
else
return false;
}
/*$判断树是否已满*/
bool TreeIsFull(const Tree *ptree)
{
if (ptree->size == MAXITEMS)
return true;
else
return false;
}
/*$返回树的项数*/
int TreeItemCount(const Tree *ptree)
{
return ptree->size;
}
/*$添加项*/
bool AddItem(const Item *pi, Tree *ptree)
{
Trnode *new_node;
if (TreeIsFull(ptree))
{
fprintf(stderr, "Tree is full!\n");
return false;
}
if (SeekItem(pi, ptree).child != NULL)
{
fprintf(stderr, "Attempted to add duplicate item\n");
return false;
}
new_node = MakeNode(pi);
if (new_node == NULL)
{
fprintf(stderr, "couldn't create node\n");
return false;
}
/*成功创建了一个新的节点*/
ptree->size++;
if (ptree->root == NULL) /*情况1:树为空*/
ptree->root = new_node; /*新节点是根节点*/
else /*情况2:树不为空*/
AddNode(new_node, ptree->root);/*在树中添加一个节点*/
return true;
}
/*$查找项*/
bool InTree(const Item *pi, const Tree *ptree)
{
return (SeekItem(pi, ptree).child == NULL )? false : true;
}
/*$删除一个项(承接上面,主要功能为将节点与特定项关联)*/
bool DeleteItem(const Item *pi, Tree *ptree)
{
Pair look;
look = SeekItem(pi, ptree);
if (look.child == NULL)
return false;
if (look.parent == NULL) //删除根节点
DeleteNode(&ptree->root);//此时根节点即为所寻找的节点
else if (look.parent->left == look.child)
DeleteNode(&look.parent->left);
else
DeleteNode(&look.parent->right);
ptree->size--;
return true;
}
/*$遍历树*/
void Traverse(const Tree *ptree, void(*pfun)(Item item))
{
if (ptree != NULL)
InOrder(ptree->root, pfun);
}
/*$清空树*/
void DeleteAll(Tree *ptree)
{
if (ptree != NULL)
DeleteAllNodes(ptree->root);
ptree->root = NULL;
ptree->size = 0;
}
使用接口
/*petclub.cpp--使用二叉树*/
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include"tree.h"
char menu(void);
void addpet(Tree *pt);
void droppet(Tree *pt);
void showpets(const Tree *pt);
void findpet(const Tree *pt);
void printitem(Item item);
void uppercase(char *str);
char *s_gets(char *st, int n);
int main()
{
Tree pets;
char choice;
InitializeTree(&pets);
while ((choice = menu()) != 'q')
{
switch (choice)
{
case 'a':addpet(&pets);break;
case 'l':showpets(&pets); break;
case 'f':findpet(&pets); break;
case 'n':printf("%d pets in club\n", TreeItemCount(&pets));
break;
case 'd':droppet(&pets); break;
default:puts("Switching error");
}
}
DeleteAll(&pets);
puts("Bye!");
return 0;
}
//
char menu(void)
{
int ch;
puts("Enter the letter corresponding to your choice:");
puts("a.add a pet l.show list of pets");
puts("n.number of pets f.find pets");
puts("d.delete a pet q.quit");
while ((ch = getchar()) != EOF)
{
while (getchar() != '\n')
continue;
ch = tolower(ch);
if (strchr("alnfdgq", ch) == NULL)
puts("please enter an a,l,n,f,d,g,q:");
else
break;
}
if (ch == EOF)
ch = 'q';
return ch;
}
void addpet(Tree *pt)
{
Item temp;
if (TreeIsFull(pt))
puts("No room in the club!");
else
{
puts("Please enter name of pet:");
s_gets(temp.petname, SLEN);
puts("Please enter petkind:");
s_gets(temp.petkind, SLEN);
uppercase(temp.petname);
uppercase(temp.petkind);
AddItem(&temp, pt);
}
}
void showpets(const Tree *pt)
{
if (TreeIsEmpty(pt))
puts("No entries!");
else
Traverse(pt, printitem);
}
void printitem(Item item)
{
printf("Pet:%-19s kind:%-19s\n", item.petname, item.petkind);
}
void findpet(const Tree *pt)
{
Item temp;
if (TreeIsEmpty(pt))
{
puts("empty!");
return;
}
puts("Please enter name:");
s_gets(temp.petname, SLEN);
puts("And then enter kind:");
s_gets(temp.petkind, SLEN);
uppercase(temp.petname);
uppercase(temp.petkind);
printf("%s the %s", temp.petname, temp.petkind);
if (InTree(&temp, pt))
printf("is a member.\n");
else
printf("is not a member.\n");
}
void droppet(Tree *pt)
{
Item temp;
if (TreeIsEmpty(pt))
{
puts("No members.");
return;
}
puts("Enter the name:");
s_gets(temp.petname, SLEN);
puts("Then enter kind:");
s_gets(temp.petkind, SLEN);
uppercase(temp.petname);
uppercase(temp.petkind);
printf("%s the %s", temp.petname, temp.petkind);
if (DeleteItem(&temp, pt))
printf("Done!\n");
else
puts("Fault!");
}
void uppercase(char *str)
{
while (*str)
{
*str = toupper(*str);
str++;
}
}
char *s_gets(char *st, int n)
{
char *ret_val;
char *find;
ret_val = fgets(st, n, stdin);
if (ret_val)
{
find = strchr(st, '\n'); //查找换行符
if (find)
*find = '\0'; //在此处放置一个空字符
else
while (getchar() != '\n')
continue; //处理输入行的剩余内容
}
return ret_val;
}