C语言编程练习:通讯录
一、目标描述:
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; }