添加项目
1、检查树中是否还有空位
2、检查树中是否已经有该项目
2、通过前两步,就可以建立一个新的节点,将项目复制到节点中,并设置此节点左右指针为NULL,再更新Tree结构的size成员
找此节点在树中的位置
如果树为空
将根节点指针指向该新节点
else
判断新项目与根项目的大小
如果新项目小于根项目,那么新项目要到左子树去
如果左子树为空
把根节点的左子指针指向新节点
else(非空)
递归新项目和左子节点项止
如果新项目大于根项目,那么新项目要到右子树去
如果右子树为空
把根节点的右子指针指向新节点
else(非空)
递归新项目和右子节点项止
删除项目
删除的节点没有子节点
此情况将其父节点的相应指针置为NULL,并用free()函数释放被删节点占用的内存
删除的节点有一个子节点
将其子节点的地址存储在删除节点的地址在它父节点中占据的位置中
删除的节点有两个子树
寻找删除节点的右子树的头应在的位置
沿着删除节点的左支向下找,沿着左子树的右支迭代查找,直到找到一个空位
然后将删除节点的右子树的头存储在这个空位上
再将删除节点的左子树的头的地址存储在删除节点的地址在它父节点中占据的位置中
DeleteNode()函数
处理三种情况:无左子节点的节点、无右子节点的节点和有两个子节点的节点
无子节点的节点可作为无左子节点的特例。因为如果该节点无左子节点,程序就将右子节点的地址赋给父指针,但如果此时该节点也没有右子节点,则其指针就为NULL,就恰好是无子节点情况的值
处理有两个子节点情况的代码首先在一个for循环中用temp指针向下查找左子树的右半边以找到一个空位,当找到一个空位的时候,将右子树依附在那儿,然后再用temp保存被删除节点的地址,接下来,将左子树依附到父节点上,然后释放temp指向的内存
输出:
Pet:B Kind:B
Pet:E Kind:E
Pet:F Kind:F
Pet:G Kind:G
Pet:H Kind:H
Pet:I Kind:I
Pet:K Kind:K
Pet:L Kind:L
Pet:N Kind:N
Pet:Q Kind:Q
petclub.c
#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);
int main(void)
{
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("Nerfville pet club membership program");
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("alrfndq",ch)==NULL)
puts("Please enter an a,l,f,n,d,or 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: ");
gets(temp.petname);
puts("Please enter pet kind: ");
gets(temp.petkind);
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("No entries!");
return;
}
puts("Please enter name of pet you wish to find: ");
gets(temp.petname);
puts("Please enter pet kind: ");
gets(temp.petkind);
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 entries!");
return;
}
puts("Please enter name of pet you wish to delete: ");
gets(temp.petname);
puts("Please enter pet kind: ");
gets(temp.petkind);
uppercase(temp.petname);
uppercase(temp.petkind);
printf("%s the %s ",temp.petname,temp.petkind);
if(DeleteItem(&temp,pt))
printf("is dropped from the club.\n");
else
printf("is not a member.\n");
}
void uppercase(char * str)
{
while(*str)
{
*str=toupper(*str);
str++;
}
}
tree.h
#ifndef _TREE_H_
#define _TREE_H_
#include <stdbool.h>
typedef struct item
{
char petname[20];
char petkind[20];
}Item;
#define MAXITEMS 10
typedef struct node
{
Item item;
struct node * left; /*指向左分支的指针 */
struct node * right; /*指向右分支的指针 */
}Node;
typedef struct tree
{
Node * root; /* 指向树根的指针 */
int size; /* 树中项目的个数 */
}Tree;
/*
函数原型
操作:把一个树初始化为空树
操作前:ptree指向一个树
操作后:该树已被初始化为空树
*/
void InitializeTree(Tree * ptree);
/*
操作:确定树是否为空
操作前:ptree指向一个树
操作后:如果树为空则函数返回true;否则返回false
*/
bool TreeIsEmpty(const Tree * ptree);
/*
操作:确定树是否已满
操作前:ptree指向一个树
操作后:如果树已满则函数返回true,否则返回false
*/
bool TreeIsFull(const Tree * ptree);
/*
操作:确定树中项目的个数
操作前:ptree指向一个树
操作后:函数返回树中项目的个数
*/
int TreeItemCount(const Tree * ptree);
/*
操作:向树中添加一个项目
操作前:pi是待添加的项目的地址
ptree指向一个已初始化的树
操作后:如果可能,函数把该项目
添加到树中并返回true;
否则函数返回false
*/
bool AddItem(const Item * pi,Tree * ptree);
/*
操作:在树中查找一个项目
操作前:pi指向一个项目
ptree指向一个已初始化的树
操作后:如果该项目在树中,则函数返回true;
否则返回false
*/
bool InTree(const Item * pi,const Tree * ptree);
/*
操作:从树中删除一个项目
操作前:pi是待删除的项目的地址
ptree指向一个已初始化的树
操作后:如果可能,函数从树中删除该项目
并返回true,否则函数返回false
*/
bool DeleteItem(const Item * pi,Tree * ptree);
/*
操作:把一个函数作用于树中每一个项目
操作前:ptree指向一棵树
pfun指向一个没有返回值的函数
该函数接受一个Item作为参数
操作后:pfun指向的函数被作用于
树中每个项目一次
*/
void Traverse(const Tree * ptree,void (* pfun)(Item item));
/*
操作:从树中删除所有节点
操作前:ptree指向一个已经初始化的树
操作后:该树为空树
*/
void DeleteAll(Tree * ptree);
#endif
tree.c
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include "tree.h"
/* 局部数据类型 */
typedef struct pair
{
Node * parent;
Node * child;
}Pair;
/* 局部函数的原型 */
static Node * 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(Node * new_node,Node * root);
static void InOrder(const Node * root,void (* pfun)(Item item));
static struct pair SeekItem(const Item * pi,const Tree * ptree);
static void DeleteNode(Node ** ptr);
static void DeleteAllNodes(Node * ptr);
/*函数定义*/
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)
{
Node * 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)
ptree->root=new_node;
else
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;
}
static void InOrder(const Node * root,void (* pfun)(Item item))
{
if(root!=NULL)
{
InOrder(root->left,pfun);
(*pfun)(root->item);
InOrder(root->right,pfun);
}
}
static void DeleteAllNodes(Node * root)
{
Node * pright;
if(root!=NULL)
{
pright=root->right;
DeleteAllNodes(root->left);
free(root);
DeleteAllNodes(pright);
}
}
static void AddNode(Node * new_node,Node * root)
{
if(ToLeft(&new_node->item,&root->item))
{
if(root->left==NULL)
{
root->left=new_node;
puts("添加成功");
}
else
AddNode(new_node,root->left);
}
else if(ToRight(&new_node->item,&root->item))
{
if(root->right==NULL)
{
root->right=new_node;
puts("添加成功");
}
else
AddNode(new_node,root->right);
}
else
{
fprintf(stderr,"location error in AddNode()\n");
exit(1);
}
}
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 Node * MakeNode(const Item * pi)
{
Node * new_node;
new_node=(Node *)malloc(sizeof(Node));
if(new_node!=NULL)
{
new_node->item=*pi;
new_node->left=NULL;
new_node->right=NULL;
}
return new_node;
}
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;
}
return look;
}
static void DeleteNode(Node ** ptr)
{
Node * temp;
puts((*ptr)->item.petname);
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);
}
}