一、目標描述:
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; }