一、目标描述:
1、建立一个通讯录,按姓名字母排序存储联系人信息。
2、可显示菜单提供显示、新增、删除、修改等功能。
3、显示:(1)显示联系人数量及全部联系人信息;(2)提供特定条件查询指定联系人信息。
4、新增:逐步提示对应信息输入。
5、删除:删除指定联系人信息。
6、修改:提供特定条件修改指定单个联系人信息:先显示原先信息,再提供选项修改对应条目。
7、通讯录信息保存在文件中。
二、目标分析:
1、项目需要排序、新增,则考虑使用二叉搜索树来建立数据堆模型。
2、该模型须提供以下具体功能模块:(1)初始化(2)新增项目(3)删除(4)查询有无(5)修改
3、信息要保存到文件中,每一次更新信息都要对应到文件中;则上述功能模块都要增加读写文件功能才能更新文件,这是一个复杂而且现阶段我很难实现的工作,只考虑下面一种很笨拙但相对简单的实现方式:在上述功能模块中:(2)新增(3)删除(5)修改功能后提供文件更新,同时文件更新不针对某条具体的(新增的或删除的或修改的)信息,而是对应功能完成后文件按整个通讯录重新写入。因此增加功能模块(6)将整个二叉树信息依序写入文件。
4、程序第一次运行,文件信息为空,通过程序新增录入信息,并且文件得以更新,这没有问题。可第二次,第三次运行呢?文件已经存在,而且已经有信息了,可程序运行之初二叉树数据堆是空的,怎样读取文件中的信息,并写入二叉树模型呢?
如果在文件中联系人信息如下设置:
"Name:""-Bir_Year:""-..."可通过文本字符串判断然后写入二叉树的节点;另外一点,选择按姓名比较建立二叉树。同时,每个联系人信息结尾用换行符进行标记。
三、功能模块的具体思路
1、初始化
先读取文本,建立二叉树联系人模型;若文本为空,则初始化空树。
2、新增
提示输入姓名,写入相关信息,建立节点,依据姓名找到合适位置插入二叉树。依据更新的二叉树,重新写入文本。
3、删除
提示输入被删姓名,删除该节点。依据更新的二叉树,重新写入文本。
4、查询有无
提示输入查询条件,找到相关信息并显示。该模块为功能2、3、5提供支持。
5、修改
提示输入被修改姓名,修改操作。依据更新的二叉树,重新写入文本。
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void IniTree();
void AddNode();
void ChoiceAdd();
void ShowTree();
int SeekName();
void ChoiceDel();
void DeleteNode();
void Choicefind();
void Choicemod();
void ShowMainInterface();
void NodeWrite();
typedef struct member
{
char name[20];
char sex;
char bir_year[5];
char bir_month[3];
char bir_day[3];
char qq[15];
}Member;
typedef struct node
{
Member *person;
struct node *left;
struct node *right;
}Node;
typedef struct tree
{
Node *root;
int numbers;
}Tree;
void ShowMainInterface()
{
printf("Input your choice:\n");
printf("a)show all friends.\n");
printf("b)add a friend's information.\n");
printf("c)modify a friend's information.\n");
printf("d)delete a friend.\n");
printf("e)look for a friend's information.\n");
printf("q)Quit.\n");
}
void IniTree(Tree *ptree)
{
FILE *fp;
Node *newnode;
int i=0;
char name[20];
char sex;
char bir_year[5];
char bir_month[3];
char bir_day[3];
char qq[15];
char ch;
fp=fopen("c.txt","r");
//如果文件不存在,则初始化二叉树
if(fp==NULL)
{
ptree->root=NULL;
ptree->numbers=0;
printf("FILE Error!\n");
}
//文件存在,则读入文件,创建二叉树节点信息
else
{
ch=getc(fp);
//每个换行符前为一个联系人信息,每行建一个节点
//读文件前,先初始化树
ptree->root=NULL;
ptree->numbers=0;
while(ch!=EOF)
{
while((ch!='\n')&&(ch!=EOF))
{
newnode=(Node*)malloc(sizeof(Node));
while(ch!='-')
{
newnode->person->name[i]=ch;
i++;
ch=getc(fp);
}
newnode->person->name[i]='\0';
//姓名信息录入完毕,重置i,继续读取下一个字符
i=0;
ch=getc(fp);
while(ch!='-')
{
newnode->person->sex=ch;
ch=getc(fp);
}
//性别信息录入完毕,重置i,继续读取下一个字符
i=0;
ch=getc(fp);
while(ch!='-')
{
newnode->person->bir_year[i]=ch;
i++;
ch=getc(fp);
}
newnode->person->bir_year[i]='\0';
//出生年信息录入完毕,重置i,继续读取下一个字符
i=0;
ch=getc(fp);
while(ch!='-')
{
newnode->person->bir_month[i]=ch;
i++;
ch=getc(fp);
}
newnode->person->bir_month[i]='\0';
//出生月信息录入完毕,重置i,继续读取下一个字符
i=0;
ch=getc(fp);
while(ch!='-')
{
newnode->person->bir_day[i]=ch;
i++;
ch=getc(fp);
}
newnode->person->bir_day[i]='\0';
//出生日信息录入完毕,重置i,继续读取下一个字符
i=0;
ch=getc(fp);
while(ch!='-')
{
newnode->person->qq[i]=ch;
i++;
ch=getc(fp);
}
newnode->person->qq[i]='\0';
//qq信息录入完毕,该联系人所有信息录入完毕,建立该联系人节点信息,插入树
newnode->left=NULL;
newnode->right=NULL;
AddNode(newnode,ptree);
//此时ch到了行末,为'-'
//继续读取下一个字符
ch=getc(fp);
}
//单行节点信息录入完毕,重置i
i=0;
ch=getc(fp);
}
}
}
//使用前须确保无相同节点
void AddNode(Node *node,Tree *ptree)
{
Node *newnode,*fathernode;
newnode=ptree->root;
while(newnode!=NULL) //找空位,并且定位空位的父节点
{
if(strcmp(node->person->name,newnode->person->name)<0)
{
fathernode=newnode;
newnode=newnode->left;
}
else
{
fathernode=newnode;
newnode=newnode->right;
}
}
if(ptree->root==NULL) //如果树为空
{
ptree->root=node;
ptree->numbers++;
}
else
{
if(strcmp(node->person->name,fathernode->person->name)<0) //说明父节点左子节点为空
{
fathernode->left=node;
ptree->numbers++;
}
else
{
fathernode->right=node;
ptree->numbers++;
}
}
}
void ChoiceAdd(Tree *ptree)
{
Node *newnode;
char namex[20];
printf("please input the name:\n");
scanf("%s",namex);
while(getchar()!='\n') continue;
if(SeekName(namex,ptree->root)==1)
printf("the person:%s is exist.\n",namex);
else
{
newnode=(Node*)malloc(sizeof(Node));
strcpy(newnode->person->name,namex);
printf("\nplease input the sex(F or M):\n");
scanf("%c",&(newnode->person->sex));while(getchar()!='\n') continue;
printf("\nplease input the bir_year:\n");
scanf("%s",newnode->person->bir_year);while(getchar()!='\n') continue;
printf("\nplease input the bir_month:\n");
scanf("%s",newnode->person->bir_month);while(getchar()!='\n') continue;
printf("\nplease input the bir_day:\n");
scanf("%s",newnode->person->bir_day);while(getchar()!='\n') continue;
printf("\nplease input the QQ:\n");
scanf("%s",newnode->person->qq);while(getchar()!='\n') continue;
newnode->left=NULL;
newnode->right=NULL;
AddNode(newnode,ptree);
printf("-----%s information recorded!---------\n",namex);
}
}
void ShowTree(const Node *root)
{
Node *newnode;
newnode=root;
if(newnode!=NULL)
{
ShowTree(newnode->left);
printf("%s--%c--%s--%s--%s--%s.\n",root->person->name,root->person->sex,
root->person->bir_year,root->person->bir_month,
root->person->bir_day,root->person->qq);
ShowTree(newnode->right);
}
}
//查找树中有无指定姓名
//若有返回1,若无返回0
int SeekName(char name[20],const Node *root)
{
Node *pnode;
if(root==NULL)
return 0;
pnode=root;
while(pnode!=NULL)
{
if(strcmp(name,pnode->person->name)<0)
{
pnode=pnode->left;
}
else if(strcmp(name,pnode->person->name)>0)
{
pnode=pnode->right;
}
else
return 1;
}
return 0;
}
void ChoiceDel(Tree *ptree)
{
Node *nodef,*nodec;
char namex[20];
printf("please input the name:\n");
scanf("%s",namex);
if(SeekName(namex,ptree->root)==0)
{
printf("the person %s is not exist!\n",namex);
}
else
{
nodec=ptree->root;
nodef=NULL;
while(nodec!=NULL)
{
if(strcmp(namex,nodec->person->name)<0)
{
nodef=nodec;
nodec=nodec->left;
}
else if(strcmp(namex,nodec->person->name)>0)
{
nodef=nodec;
nodec=nodec->right;
}
else
break;
}//找到该节点及其父节点
if(nodef==NULL)
DeleteNode(&ptree->root);
else if(nodef->left==nodec)
DeleteNode(&nodef->left);
else
DeleteNode(&nodef->right);
ptree->numbers--;
printf("--------%s is deleted!---------\n",namex);
}
}
//删除结点函数,参数如何描述?
//删除操作后被删除结点的父节点的“指向被删结点的指针成员”要重新赋值
//所以要用指向“父节点指针成员”的指针去描述
//而父节点指针成员本身是一个Node*指针型,所以参数类型为Node **
//注意:这里的ptr是指向父节点指针成员(指向被删结点)的指针类型
//*ptr描述的是父节点中指向被删结点的指针成员,也即被删结点的地址指针类型
//**ptr则是描述被删除的结点类型
void DeleteNode(Node **ptr)
{
Node *temp;
//*ptr为被删结点父节点的指针成员,该成员指向被删结点,
//(*ptr)->left即指向被删结点的左子节点
//若其左子节点为空,将其右子节点链接到父节点原先指向被删结点的指针成员
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);
}
}
void Choicefind(Tree *ptree)
{
Node *nodef,*nodec;
char namex[20];
printf("please input the name:\n");
scanf("%s",namex);
if(SeekName(namex,ptree->root)==0)
{
printf("the person %s is not exist!\n",namex);
}
else
{
nodec=ptree->root;
nodef=NULL;
while(nodec!=NULL)
{
if(strcmp(namex,nodec->person->name)<0)
{
nodef=nodec;
nodec=nodec->left;
}
else if(strcmp(namex,nodec->person->name)>0)
{
nodef=nodec;
nodec=nodec->right;
}
else
break;
}//找到该节点及其父节点
printf("the person:%s information is followed:\n");
printf("name:%s\n",nodec->person->name);
printf("sex:%c\n",nodec->person->sex);
printf("bir_year:%s\n",nodec->person->bir_year);
printf("bir_month:%s\n",nodec->person->bir_month);
printf("bir_day:%s\n",nodec->person->bir_day);
printf("qq:%s\n",nodec->person->qq);
}
printf("input any key to continue...\n");
getch();
}
void Choicemod(Tree *ptree)
{
Node *nodef,*nodec;
char namex[20];
char ch;
printf("please input the name:\n");
scanf("%s",namex);
if(SeekName(namex,ptree->root)==0)
{
printf("the person %s is not exist!\n",namex);
}
else
{
nodec=ptree->root;
nodef=NULL;
while(nodec!=NULL)
{
if(strcmp(namex,nodec->person->name)<0)
{
nodef=nodec;
nodec=nodec->left;
}
else if(strcmp(namex,nodec->person->name)>0)
{
nodef=nodec;
nodec=nodec->right;
}
else
break;
}//找到该节点及其父节点
printf("--------------------Please choose--------------------\n");
printf("a)----------modify name----%s\n",nodec->person->name);
printf("b)----------modify sex----%c\n",nodec->person->sex);
printf("c)----------modify bir_year----%s\n",nodec->person->bir_year);
printf("d)----------modify bir_month----%s\n",nodec->person->bir_month);
printf("e)----------modify bir_day----%s\n",nodec->person->bir_day);
printf("f)----------modify qq----%s\n",nodec->person->qq);
printf("q)---------------quit to upperlevel------------------\n");
ch=getch();
printf("your choice is %c.\n",ch);
while(getchar()!='\n') continue;
while(ch!='q')
{
while(ch!='a'&&ch!='b'&&ch!='c'&&ch!='d'&&ch!='e'&&ch!='f'&&ch!='q')
{
printf("input a or b or c or d or e or f or q.\n");
ch=getchar();
printf("your choice is %c.\n",ch);
}
switch(ch)
{
case 'a':
printf("input %s new name:",nodec->person->name);
scanf("%s",nodec->person->name);
while(getchar()!='\n') continue;
break;
case 'b':
printf("input %s new sex:",nodec->person->name);
scanf("%c",&(nodec->person->sex));
while(getchar()!='\n') continue;
break;
case 'c':
printf("input %s new bir_year:",nodec->person->name);
scanf("%s",nodec->person->bir_year);
while(getchar()!='\n') continue;
break;
case 'd':
printf("input %s new bir_month:",nodec->person->name);
scanf("%s",nodec->person->bir_month);
while(getchar()!='\n') continue;
break;
case 'e':
printf("input %s new bir_day:",nodec->person->name);
scanf("%s",nodec->person->bir_day);
while(getchar()!='\n') continue;
break;
case 'f':
printf("input %s new QQ:",nodec->person->name);
scanf("%s",nodec->person->qq);
while(getchar()!='\n') continue;
break;
case 'q':
break;
}
if(ch!='q')
{
printf("--------------------Please choose--------------------\n");
printf("a)----------modify name----%s\n",nodec->person->name);
printf("b)----------modify sex----%c\n",nodec->person->sex);
printf("c)----------modify bir_year----%s\n",nodec->person->bir_year);
printf("d)----------modify bir_month----%s\n",nodec->person->bir_month);
printf("e)----------modify bir_day----%s\n",nodec->person->bir_day);
printf("f)----------modify qq----%s\n",nodec->person->qq);
printf("q)---------------quit to upperlevel------------------\n");
ch=getch();
printf("your choice is %c.\n",ch);
}
}
}
}
void NodeWrite(const Node *node)
{
FILE *fp;
fp=fopen("c.txt","a");
fprintf(fp,"%s",node->person->name);
putc('-',fp);
putc(node->person->sex,fp);
putc('-',fp);
fprintf(fp,"%s",node->person->bir_year);
putc('-',fp);
fprintf(fp,"%s",node->person->bir_month);
putc('-',fp);
fprintf(fp,"%s",node->person->bir_day);
putc('-',fp);
fprintf(fp,"%s",node->person->qq);
putc('-',fp);
putc('\n',fp);
fclose(fp);
}
void TreeWrite(const Node *root)
{
Node *pnode;
pnode=root;
if(pnode!=NULL)
{
TreeWrite(pnode->left);
NodeWrite(pnode);
TreeWrite(pnode->right);
}
}
int main(void)
{
//变量设置区----------------------------------------
Tree *ctree;
char ch;
//变量设置结束--------------------------------------
//程序信息区-----------------------------------------
printf("*******************************************************************\n");
printf("-----------------------------Address Book--------------------------\n");
printf("------------------------------Version1.0---------------------------\n");
printf("-----------------------------By TSEMBRACE--------------------------\n");
printf("*******************************************************************\n");
//程序信息结束---------------------------------------
//初始化数
IniTree(ctree);
//主操作界面区---------------------------------------
ShowMainInterface();
ch=getch();
while(ch!='q')
{
while((ch!='a')&&(ch!='b')&&(ch!='c')&&(ch!='d')&&(ch!='e'))
{
printf("choose a or b or c or d or e or q!\n");
ch=getch();
if(ch=='q')
break;
}
switch(ch)
{
case 'a':
if(ctree->root==NULL)
printf("-----------There is no information.------------\n");
else
{printf("---------My Address List is followed:---------\n");
ShowTree(ctree->root);
printf("------------------My Address List end-------------------\n");
}
printf("Total number is %d.\n",ctree->numbers);
ShowMainInterface();
printf("please choose:\n");
ch=getch();
printf("your choose is:%c\n",ch);
break;
case 'b':ChoiceAdd(ctree);ShowMainInterface();
printf("please choose:\n");
ch=getch();
printf("your choose is:%c\n",ch);
break;
case 'c':Choicemod(ctree);ShowMainInterface();
printf("please choose:\n");
ch=getch();
printf("your choose is:%c\n",ch);
break;
case 'd':ChoiceDel(ctree);ShowMainInterface();
printf("please choose:\n");
ch=getch();
printf("your choose is:%c\n",ch);
break;
case 'e':Choicefind(ctree);ShowMainInterface();
printf("please choose:\n");
ch=getch();
printf("your choose is:%c\n",ch);
break;
case 'q':
printf("your choose is:q\n");
break;
}
}
TreeWrite(ctree->root);
printf("GoodBye!\ninput any key to quit.");
//主操作界面结束-------------------------------------
getch();
return 0;
}