散列表实现通讯录
1、项目研究背景与意义
背景:随着信息活动在国民经济中主导地位的确立和信息产业的崛起,信息资源管理作为一个专有名词和独立的学科逐渐发展起来。如何积极开发、合理配置和有效利用信息资源,日益成为社会中急需解决的问题。由于计算机和通信技术的高速发展,推广应用计算机进行信息管理成为推动信息化工作的重要内容,信息管理系统正是应用计算机信息化过程中出现的新事物。它能够提供信息、支持企业和组织的运行,对管理者作出决策有重要的意义。信息管理系统用于管理中可以大大减轻管理人员的工作负担,提高工作效率。使管理更加程序化,科学化。
对一个组织而言,内部管理的好坏直接关系到组织的存在与良好运行,而内部管理中非常重要的一项就是对他人的连续联系,他人的具体情况,如:手机号、姓名、家庭住址......;一旦工作人员没有及时出现在自己岗位时或因其它情况发生变化时,可以迅速连续或找到本人及其家人了解情况。本系统是针对通信录管理系统编写的。对于许多人来说,已经认识到一个好的通信录是很必要的,可以方便和其他人的联系;但是应用计算机来进行管理还无法实现,所以就需要专门的管理软件来帮助实现。、
随着科技的进步和信息产业的飞速发展,通讯录成为了现代生活中一个重要的工具。本通讯录管理系统利用计算机对通信录进行统一管理,包括添加、修改、查询等功能,实现通信录管理工作的系统化、规范化和自动化,为人们的工作和生活提供便利。整个系统程序采用C语言实现,C语言是目前国际上比较流行的计算机高级编程语言之一,因其简洁、使用方便且具备强大的功能而受到编程人员的普通青睐。它既适合作为系统描述语言,也可用来编写系统软件,还可用来编写应用软件。
意义:计算机已经成为我们学习和工作的得力助手,使用其可方便的管理通讯录。目前,大多数人的通讯管理水平还停留在纸介质的基础上,这样的机制已经不能适应时代的发展了,他浪费了大量的人力物力,在信息时代这种传统的管理方法必然被计算机为基础的信息管理所取代。
开发这一系统的好处大约有以下几点:
第一、可以安全、高效的存储大量的通讯录信息;
第二、只需一档案录入即可完成操作系统,节省人力;
第三、可以迅速的查到所需的通讯录信息。
2、系统需求分析
根据用户需求,通讯录需要长期保存联系人信息,且用户可实现对联系人的添加、删除、修改和查找等功能。
首先,需要创建通讯录。
Create ( )的功能:创建新的通讯录。
为长期保存联系人,需要以文件形式存储,并且可以随时对文件中的信息进行读取。
本系统应完成以下几方面的功能:
Load ( )的功能:从指定文件中读取通讯录中的记录。
Save ( )的功能:保存通讯录中的所有记录到指定文件中。
当通讯录中信息为空,需要首先对通讯录进行初始化。
Start ( )的功能:初始化通讯录。
需要添加、删除、修改、查找联系人时,可以随时进行增、删、改、查等功能。
newnumz( )的功能:在通讯录写入新的信息,并返回选单。
Findnum ( )的功能:查询某人的信息,如果找到了,则显示该人的信息,如果没有则提示通讯录中没有此人的信息,并返回选单。
Alter ( )的功能:修改某人的信息,如果未找到要修改的人,则提示通讯录中没有此人的信息, 并返回选单。
Delete ( )的功能:删除某人的信息,如果未找到要删除的人,则提示通讯录中没有此人的信息并返回选单。
根据用户的需求,有时需要显示通讯录中的全部联系人信息。
List ( )的功能:显示通讯录中的所有记录。
3、概要设计
4、详细设计
4.1结构体设计
个人信息以结构体实现,包括电话号码、姓名和地址。
struct xinxi
{
int num;
char name[10];
char address[10];
};//个人信息结构体
散列表以顺序表实现,可以存储50个联系人的信息。
struct hash
{
int max;
int len;
Data h[50];
};//散列表
4.2创建散列表Create()
创建散列表Create(),为散列表申请空间,并把所有号码置为0.
phash creat(){
int i;
phash p=(phash)malloc(sizeof(struct hash));
if(p!=NULL){
p->max=50;
p->len=0;
for(i=0;i<50;i++) {p->h[i].num=0;} //关键码全部置零
return p;
}
}
4.3检索函数Find()
检索函数Find(),检索电话号码在散列表中是否存在。若存在,则通过position返回地址,并返回1;若不存在,返回0.
int find(phash p,int num,int *position){
int d,inc;
d=num%50;//散列函数
for(inc=0;inc<50;inc++){
if(p->h[d].num==num){
*position=d;//检索成功
return 1;
}
else if(p->h[d].num==0){
*position=d;//检索失败
return 0;
}
d=(d+1)%50;
}
*position=-1;//散列表溢出
return 0;
}
4.4插入函数Append()
插入函数Append(),若所要插入的联系人的号码已存在,则输出联系人已存在;否则将联系人信息插入到应在位置。
int Append(phash p,Data x){
int position;
if(find(p,x.num,&position)==1)//散列表中已经存在
{
printf("发现已经存在!\n");
}
else if(position!=-1){
p->h[position]=x;//插入信息
p->len++;
}
else return 0;
return 1;
}
4.5初始化函数start()
初始化函数start(),循环写入联系人信息保存至临时结构体st,并调用插入函数Append(),将信息插入到散列表中。
int start(phash p){
int i;
Data st;
printf("请输入三名联系人的信息!(电话号码,姓名,地址,空格隔开)\n");
for(i=0;i<3;i++)
{
scanf("%d %s %s",&st.num,&st.name,&st.address);
Append(p,st);
}
return 1;
}
4.6查找联系人函数Findnum()
查找联系人函数Findnum(),输入联系人号码通过调用Find()函数来检索该联系人信息是否存在。若存在则输出联系人信息;若不存在,则输出所查找联系人不存在。
int findnum(phash p){
int i,num,position;
printf("输入要查询的联系人的号码!\n");
scanf("%d",&num);
if(find(p,num,&position)==1)
{
printf("%d\t%s\t%s\n",num,p->h[position].name,p->h[position].address);
}
else printf("要查找的联系人不存在\n");
return 1;
}
4.7添加联系人函数newnum()
添加联系人函数newnum(),输入要插入的联系人信息,通过调用插入函数Append(),若联系人已存在,则输出联系人存在提示;若不存在,则将联系人信息添加到通讯录。
int newnum(phash p){
int num,position;
Data n;
printf("输入要新建的联系人的号码!\n");
scanf("%d",&num);
if(find(p,num,&position)==1)//检索联系人是否存在
{printf("联系人存在!\n");
return 0;
}
else{
n.num=num;
printf("请输入需要新建联系人的信息!(姓名 地址,空格隔开)\n");
scanf("%s %s",&n.name,&n.address);
Append(p,n);
printf("新建联系人完成!\n");
return 1;
}
}
4.8删除函数Delete()
删除函数Delete(),删除一个元素后会产生空位,因为有可能因碰撞导致其余联系人不再以散列表形式存储,需逐项查找空位后面的元素把所碰撞元素赋值到空位,如此循环下去,直到构成一个新的散列表。通过调用检索函数find()返回删除元素所在位置position,记为i,删除该元素后用j标记空位,用(i++)%50来查找空位后元素,用r来表示i标记位置的元素未发生碰撞时应在的位置。在for循环中通过使用3个if语句来排除不受影响的元素,而后将选出的元素赋值到相应位置。
int Delete(phash p){
int num,i,j,r;//num:要删除的联系人号码;j:标记空位;i:移动查找是否碰撞;r:i的联系人号码未发生碰撞时应在位置。
int position;
printf("输入要删除的联系人的号码!\n");
scanf("%d",&num);
if(find(p,num,&position)==1){
i=position;
for(;;){
p->h[i].num=0;//删除i产生一个空位。
j=i;//j存放空位位置,从后面的元素中选出一个元素填补空位
for(;;){
i=(++i)%50;
if(p->h[i].num==0)//若遇到未使用的位置则调整结束
{
printf("联系人已经删除!\n");
return 1;
}
r=p->h[i].num%50;//r为i位置中的元素未发生碰撞应在位置
///
//若r位于空位和当前位置i之间,则说明该元素不受影响,则跳出寻找下一个
if(j
continue;
if(j>i && j
continue;
if(j>i && r<=i)
continue;
//以上3条语句保证了r位于i与j之间
break;
}
p->h[j]=p->h[i];//将选择的元素赋值到空位
}
}
else {printf("不存在该人!\n");}
return 1;
}
4.9修改联系人函数alter()
修改联系人函数alter(),输入联系人号码通过调用find()函数来检索,若该联系人信息存在,则将更新后的信息保存至通讯录;若不存在,则输出不存在该人。
int alter(phash p){
int num;
int position;
printf("输入要修改的联系人的号码!\n");
scanf("%d",&num);
if(find(p,num,&position)==1){//检索是否存在该联系人
p->h[position].num=num;
printf("请输入需要修改的信息!(姓名 地址,空格隔开)\n");
scanf("%s %s",&p->h[position].name,&p->h[position].address);
}
else
{
printf("不存在该人!\n");
}
return 1;
}
4.10显示函数list()
显示函数list(),将散列表中的所有联系人信息全部输出到界面。
int list(phash p){
int i;
for(i=0;i<50;i++){
if(p->h[i].num!=0)
printf("%d\t%s\t%s\n",p->h[i].num,p->h[i].name,p->h[i].address);
}
return 1;
}
4.11保存文件函数save()
保存文件函数save(),当文件已存在时,格式化输出散列表中的联系人信息到指定文件“xinxi.txt”。当文件不存在时,自动创建新文件“xinxi.txt”并格式化输出。
int save(phash p){
int i;
FILE *fout;
if((fout=fopen("xinxi.txt","w"))==NULL)//判断文件是否存在
{
printf("写入文件失败!\n");
return 0;
}
for(i=0;i<50;i++)
{ if(p->h[i].num != 0)//判断联系人是否存在
fprintf(fout,"%d %s %s\n",p->h[i].num,p->h[i].name,p->h[i].address);//输出存在的联系人
}
fclose(fout);//关闭文件
printf("文件已保存\n");
return 1;
}
4.12读取函数load()
读取函数load()当文件存在时并且未到达文件末尾,循环读取联系人信息到临时存储区temp,然后调用插入函数Append(),把联系人信息插入到散列表。
int load(phash p){
FILE *fin;
Data temp;
int i;
if((fin=fopen("xinxi.txt","r"))==NULL)//判断文件是否存在
{
printf("文件读取失败!\n");
return 0;
}
while(!feof(fin))//判断文件是否结束
{
i=fscanf(fin,"%d %s %s",&temp.num,&temp.name,&temp.address);//读取联系人信息
if(i==-1) break;
else Append(p,temp);//把读取的信息插入散列表
}
fclose(fin);
printf("文件读取成功\n");
return 1;
}
5、调试分析
开始界面:
试验初始化功能:
试验保存文件功能:
试验读取功能:
试验显示功能:
试验新建功能:
试验查询功能:
试验查询异常数据:
试验删除功能:
试验删除功能结果是否正确:
试验删除异常数据:
试验修改异常数据:
试验修改功能:
试验修改功能结果是否正确:
6.问题及难点所在
创建函数的难点:为散列表申请空间后,所有位置均为空值,由于在检索函数及插入函数中都要对散列表中每个位置的元素及要操作的元素进行比较,当位置为空比较时会生成乱码,干扰下一步的操作。
改进方法是:将所有位置均赋值为0.
检索函数的难点:在查找、新建、删除等功能中所要操作元素及其对散列表中对应位置是否为空及散列表是否溢出等情况均未知。无法进行下一步操作。
改进方法:定义检索函数根据用户的号码进行散列检索,用散列函数来逐项查找位置,若当前位置已存在或为空时,返回当前位置;若散列表以溢出,则将当前位置赋值为-1.
添加联系人信息是个难点,要先输入要添加的联系人号码,调用Find()函数来检索该联系人在散列表中是否已经存在,若存在,输出“联系人存在”,结束该程序,若不存在,将添加联系人呢相关信息保存到结构体内,通过调用插入函数Append()添加联系人信息。
保存和读取函数是一个难点:在保存文件函数中,使用fopen函数打开文件,对散列表进行遍历,当表中有元素时,使用fprintf()函数,格式化输出到“xinxi.txt”文件,然后用fclose()函数关闭文件。在读取文件时,使用fopen()函数打开文件,当文件未到达末尾,就格式化读取信息到临时结构体,然后调用插入函数Append(),把信息存放到散列表中,最后用fclose()函数关闭文件。
删除函数是一个难点:不能简单的将要删除的结点的电话号码直接置为0,因为为0是检索失败的根据,这样直接置0,会导致碰撞的元素检索失败。
解决方法:1:在被删除结点做标记(例如将关键码改为负值),不是真的删除,这样,做了多次删除后,形式上散列表是满的,但实际上是很空的。
2:绕过删除操作。把要删除号码置为0,然后保存文件,重新创建散列表,读取文件,这样新建了一个散列表,从而绕过了删除的麻烦讨论。
3:直接删除元素,产生空位,通过移动元素,使碰撞关系仍然成立。这也是我们采用的方法。我们通过输入联系人号码调用find()函数进行检索,若该联系人存在,将该联系人的信息删除并返回当前位置赋值给i,后用j=i标记当前空位置,用i++继续向下查找,用r表示i联系人号码未发生碰撞应在位置。用3个if语句依次排除不受影响的元素,当r位于j与i之间时,所标记的元素即为不需要调整的元素。后用for循环继续查找,直到出现未使用的位置。
7、算法设计的思想
整体思想:
为了方便的实现快速查找,算法中用到了数据结构中“字典的散列表示”这一章节的知识,基本思想是:选择一个从关键码到地址的散列函数h,对于每个关键码为key的元素,计算出h(key),期望把对应的元素存储到h(key)指示的地址上,如果两个不相等的关键码key1和key2,用散列函数h计算得到相同的散列地址(即h(key1)=h(key2)),此现象即为碰撞,为了实现散列法必须解决存储时碰撞的问题,处理碰撞需要付出时间和空间代价,因此要提高散列法处理效率,就应该尽量减少碰撞。算法中对于碰撞的处理使用的是线性探查法,即将基本存储区看作一个循环表。若在地址为d=h(key)的单元发生碰撞,则依次探查下述地址单元:d+1,d+2,....,m-1,0,1,....d-1(m为基本存储区的长度)直到找到一个空单元或查找到关键码为key的元素为止。如果从单元d开始探查,查找一遍后,又回到地址d,则表示基本存储区已经溢出。
本算法中采用的散列函数为h(key)=key%50.
7.1 结构体设计
需要包括联系人的电话号码,姓名和住址。
7.2创建散列表create()
创建函数的思想:由于散列表创建后要方便用户检索及各项操作,所以在创建之后将所有的空位置全部赋值为0以方便下一步的操作。
7.3检索函数find()
检索函数的思想:在新建、查找、删除等功能中所操作元素当前位置是否为空以及为空时操作对象的位置等未知,所要定义检索函数来实现此功能。我们设计通过输入用户号码num来进行散列检索,用(num)%50来查找应在位置,若查找成功,则返回1,否则若所在位置号码为空,则返回0,并将当前元素位置赋值给d;若既不为1,也不为0,继续对下一个位置进行查找。
7.4插入函数Append()
插入函数的思想:由于所要插入元素应在位置是否为空未知,所以调用检索函数来判断,若已存在,则返回;否则将元素插入到该位置。
7.5初始化函数start()
初始化函数的思想:定义结构体st来临时存储信息,后调用插入函数Append()来将所有信息插入到规定位置。
7.6查找联系人函数findnum()
为查找到联系人的相关信息,输入要查询的联系人的号码,通过调用Find()函数来检索该联系人信息是否存在。若存在,则输出联系人信息;若不存在,则输出所查找联系人不存在。
7.7添加联系人函数newnum()
为添加联系人信息,先输入要添加的联系人号码,调用Find()函数来检索该联系人在散列表中是否已经存在,若存在,输出“联系人存在”,结束该程序,若不存在,将添加联系人呢相关信息保存到结构体内,通过调用插入函数Append()添加联系人信息。
7.8删除函数Delete()
我们通过输入联系人号码调用find()函数进行检索,若该联系人存在,将该联系人的信息删除并返回当前位置赋值给i,后用j=i标记当前空位置,用i++继续向下查找,用r表示i联系人号码未发生碰撞应在位置。用3个if语句依次排除不受影响的元素,当r位于j与i之间时,所标记的元素即为不需要调整的元素。后用for循环继续查找,直到出现未使用的位置。
7.9修改函数alter()
为修改联系人信息,先输入要修改的联系人号码,通过调用find()函数来检索该联系人在散列表中是否已经存在,若该联系人存在,请输入需要修改的信息保存至通讯录;若不存在,则输出“不存在该人”。
7.10显示函数list()
设置循环,从散列表中的第一个位置依次向后检索,若所检索位置非空,将散列表中信息输出。
6、算法流程图
9:总结
由于时间紧迫和个人能力的不足,所做的程序还有极大的改善空间,只能算是勉强达到要求罢了。例如存储的电话号码仅有五位,这在实际使用中是远远不够的,还有如果不按照要求输入信息,可能产生未知错误,程序的健壮性不够。
此次课程设计,感触很多,虽然在做程序的时候由于基础知识掌握不牢,吃了很多苦头,但是总体来说还是甜多于苦,让我知道了我离实际应用的差距。在一次次的修改与检查中,巩固了我许多知识,让我明白了只有理论与实践结合,才能更好的掌握知识,才能真正的做出合格的产品。
本次课程设计,让我进一步明白了应用程序是怎么产生的,从需求分析到详细设计,只有清晰的结构,才能产生合格的程序,课程设计把我以前学到的知识第一次结合起来,使我第一次感觉到编程不只是精细的绣花,更是纵观全局,运筹帷幄的战争,只有大的方向和结构清楚,才能打赢这场战争。
本次课程设计,极大的提升了我的实际动手能力和独立思考能力。在删除函数的设计过程中,我就想过三种方法,虽然不一定能达到要求,但是三种完全不同的方法,极大的锻炼了我发散思维能力,使我学到了很多。对与如此简单的一个通讯录,已经让我焦头烂额,苦不堪言了,那些更高级的软件该有多么复杂啊,不由得对程序员们产生了深深的敬意,也对自己的能力有了一个清晰的认识,我将继续努力学习编程知识,我相信我能在这条路上走的更远!
10:附录:c语言代码
1 #include
2 #include
3
4 structxinxi;5 structxinxi6 {7 intnum;8 char name[10];9 char address[10];10 };//个人信息结构体
11 typedef structxinxi Data;12
13 structhash{14 intmax;15 intlen;16 Data h[50];17 };//散列表
18 typedef struct hash *phash;19
20
21
22 /*
23 Menu() 的功能:显示英文提示选单。24 Quit() 的功能:退出选单。25 /Create() 的功能:创建新的通讯录。26 /Append() 的功能:在通讯录写入新的信息,并返回选单。27 /Find() 的功能:查询某人的信息,如果找到了,则显示该人的信息,如果没有则提示通讯录中没有此人的信息,并返回选单。28 /Alter() 的功能:修改某人的信息,如果未找到要修改的人,则提示通讯录中没有此人的信息,并返回选单。29 /Delete() 的功能:删除某人的信息,如果未找到要删除的人,则提示通讯录中没有此人的信息,并返回选单。30 /List() 的功能:显示通讯录中的所有记录。31 /Save() 的功能:保存通讯录中的所有记录到指定文件中。32 /Load() 的功能:从指定文件中读取通讯录中的记录。33 */
34
35 ///
36 phash creat();37 intAppend(phash p,Data x);38 int find(phash p,int num,int *position);39 intalter(phash p);40 intDelete(phash p);41 intlist(phash p);42 intfindnum(phash p);43 intsave(phash p);44 intload(phash p);45 intstart(phash p);46 intnewnum(phash p);47 intmenu(phash p);48 /函数声明49
50
51 /
52 phash creat(){53 inti;54 phash p=(phash)malloc(sizeof(structhash));55 if(p!=NULL){56 p->max=50;57 p->len=0;58 for(i=0;i<50;i++) {p->h[i].num=0;} //关键码全部置零
59 returnp;60 }61 }62 ///创建散列表///63
64
65 66 intAppend(phash p,Data x){67 intposition;68 if(find(p,x.num,&position)==1)//散列表中已经存在
69 {70 printf("发现已经存在!\n");71 }72 else if(position!=-1){73 p->h[position]=x;//插入信息
74 p->len++;75 }76 else return 0;77 return 1;78 }79 //散列表的插入///80
81
82 /
83 int find(phash p,int num,int *position){84 intd,inc;85 d=num%50;//散列函数
86 for(inc=0;inc<50;inc++){87 if(p->h[d].num==num){88 *position=d;//检索成功
89 return 1;90 }91 else if(p->h[d].num==0){92 *position=d;//检索失败
93 return 0;94 }95 d=(d+1)%50;96 }97 *position=-1;//散列表溢出
98 return 0;99 }100 /散列表的检索//101
102
103
104 ///105 intalter(phash p){106 intnum;107 intposition;108 printf("输入要修改的联系人的号码!\n");109 scanf("%d",&num);110
111 if(find(p,num,&position)==1){//检索是否存在该联系人
112 p->h[position].num=num;113 printf("请输入需要修改的信息!(姓名 地址,空格隔开)\n");114 scanf("%s %s",&p->h[position].name,&p->h[position].address);115 }116 else
117 {118 printf("不存在该人!\n");119 }120
121 return 1;122 }123 /修改联系人信息///124
125
126
127 //
128
129 intDelete(phash p){130 int num,i,j,r;//num:要删除的联系人号码;j:标记空位;i:移动查找是否碰撞;r:i的联系人号码未发生碰撞时应在位置。
131 intposition;132 printf("输入要删除的联系人的号码!\n");133 scanf("%d",&num);134
135 if(find(p,num,&position)==1){136 i=position;137 for(;;){138 p->h[i].num=0;//删除i产生一个空位。
139 j=i;//j存放空位位置,从后面的元素中选出一个元素填补空位
140 for(;;){141 i=(++i)%50;142 if(p->h[i].num==0)//若遇到未使用的位置则调整结束
143 {144 printf("联系人已经删除!\n");145 return 1;146 }147 r=p->h[i].num%50;//r为i位置中的元素未发生碰撞应在位置
148 ///149 //若r位于空位和当前位置i之间,则说明该元素不受影响,则跳出寻找下一个
150 if(ji && ji && r<=i)155 continue;156 //以上3条语句保证了r位于i与j之间
157 158 break;159 }160 p->h[j]=p->h[i];//将选择的元素赋值到空位
161 }162
163
164
165 }166 else {printf("不存在该人!\n");}167 return 1;168 }169
170
171 /删除联系人/
172
173
174
175 176 intlist(phash p){177 inti;178 for(i=0;i<50;i++){179 if(p->h[i].num!=0)180 printf("%d\t%s\t%s\n",p->h[i].num,p->h[i].name,p->h[i].address);181 }182 return 1;183 }184 ///输出所有联系人//
185
186
187
188 ///
189 intsave(phash p){190 inti;191 FILE *fout;192 if((fout=fopen("xinxi.txt","w"))==NULL)//判断文件是否存在
193 {194 printf("写入文件失败!\n");195 return 0;196 }197 for(i=0;i<50;i++)198 { if(p->h[i].num != 0)//判断联系人是否存在
199 fprintf(fout,"%d %s %s\n",p->h[i].num,p->h[i].name,p->h[i].address);//输出存在的联系人
200 }201 fclose(fout);//关闭文件
202 printf("文件已保存\n");203 return 1;204 }205 //保存联系人到指定文件
206
207
208 ///
209 intload(phash p){210 FILE *fin;211 Data temp;212 inti;213 if((fin=fopen("xinxi.txt","r"))==NULL)//判断文件是否存在
214 {215 printf("文件读取失败!\n");216 return 0;217 }218 while(!feof(fin))//判断文件是否结束
219 {220 i=fscanf(fin,"%d %s %s",&temp.num,&temp.name,&temp.address);//读取联系人信息
221 if(i==-1) break;222 else Append(p,temp);//把读取的信息插入散列表
223 }224 fclose(fin);225 printf("文件读取成功\n");226 return 1;227 }228 ///读取指定文件的信息229
230
231 /
232 intstart(phash p){233 inti;234 Data st;235 printf("请输入三名联系人的信息!(电话号码,姓名,地址,空格隔开)\n");236 for(i=0;i<3;i++)237 {238 scanf("%d %s %s",&st.num,&st.name,&st.address);239 Append(p,st);240
241 }242 return 1;243 }244 初始化信息
245
246
247 //
248 intnewnum(phash p){249 intnum,position;250 Data n;251 printf("输入要新建的联系人的号码!\n");252 scanf("%d",&num);253 if(find(p,num,&position)==1)//检索联系人是否存在
254 {printf("联系人存在!\n");255 return 0;256 }257 else{258 n.num=num;259 printf("请输入需要新建联系人的信息!(姓名 地址,空格隔开)\n");260 scanf("%s %s",&n.name,&n.address);261 Append(p,n);262 printf("新建联系人完成!\n");263 return 1;264 }265 }266 新建联系人并插入散列表/267
268
269
270 ///271 intfindnum(phash p){272 inti,num,position;273 printf("输入要查询的联系人的号码!\n");274 scanf("%d",&num);275 if(find(p,num,&position)==1)276 {277 printf("%d\t%s\t%s\n",num,p->h[position].name,p->h[position].address);278 }279 else printf("要查找的联系人不存在\n");280 return 1;281 }282 /查找联系人并输出信息//283
284
285
286 ///287 intmenu(phash p){288 inti;289
290 printf("********请输入要进行的操作!*********\n\n0-退出通讯录选单\n1-新建联系人\n2-查找联系人\n3-删除联系人\n4-修改联系人的相关信息\n5-保存通讯录至文件\n6-读取文件中的联系人信息\n7-显示通信录的全部信息\n");291 scanf("%d",&i);292
293 switch(i)294 {295 case 0: exit(0); break;296 case 1: newnum(p); break;297 case 2: findnum(p); break;298 case 3: Delete(p); break;299 case 4: alter(p); break;300 case 5: save(p); break;301 case 6: load(p); break;302 case 7: list(p); break;303 default : printf("选择有误!\n");304 }305 return 1;306 }307 ///选单///308
309
310 intmain(){311
312 inti;313 phash h;314 h=creat();315 printf("********************欢迎使用通讯录存储系统**************************\n");316 printf("* 当联系人信息文件不存在时,请初始化通讯录,存入联系人的相关信息。*\n");317 printf("* 当联系人信息文件存在时,请读取信息文件。 *\n");318 printf("* 在执行完所有操作时,请保存文件后退出 *\n");319 printf("* 可存储号码50个 *\n");320 printf("* 号码长度为5位 *\n");321 printf("* 姓名,地址为10个字符 *\n");322 printf("********************************************************************\n");323 printf("\n");324 printf("请选择要进行的操作!1-初始化,2-读取联系人\n");325 scanf("%d",&i);326 if(i==1)327 start(h);328 else if(i==2)329 load(h);330 else
331 printf("输入错误!\n");332 for(;;)333 {334 menu(h);335 }336 return 1;337 }
/
80
81
82 /
83 int find(phash p,int num,int *position){
84 int d,inc;
85 d=num%50;//散列函数
86 for(inc=0;inc<50;inc++){
87 if(p->h[d].num==num){
88 *position=d;//检索成功
89 return 1;
90 }
91 else if(p->h[d].num==0){
92 *position=d;//检索失败
93 return 0;
94 }
95 d=(d+1)%50;
96 }
97 *position=-1;//散列表溢出
98 return 0;
99 }
100 /散列表的检索//
101
102
103
104 ///
105 int alter(phash p){
106 int num;
107 int position;
108 printf("输入要修改的联系人的号码!\n");
109 scanf("%d",&num);
110
111 if(find(p,num,&position)==1){//检索是否存在该联系人
112 p->h[position].num=num;
113 printf("请输入需要修改的信息!(姓名 地址,空格隔开)\n");
114 scanf("%s %s",&p->h[position].name,&p->h[position].address);
115 }
116 else
117 {
118 printf("不存在该人!\n");
119 }
120
121 return 1;
122 }
123 /修改联系人信息///
124
125
126
127 //
128
129 int Delete(phash p){
130 int num,i,j,r;//num:要删除的联系人号码;j:标记空位;i:移动查找是否碰撞;r:i的联系人号码未发生碰撞时应在位置。
131 int position;
132 printf("输入要删除的联系人的号码!\n");
133 scanf("%d",&num);
134
135 if(find(p,num,&position)==1){
136 i=position;
137 for(;;){
138 p->h[i].num=0;//删除i产生一个空位。
139 j=i;//j存放空位位置,从后面的元素中选出一个元素填补空位
140 for(;;){
141 i=(++i)%50;
142 if(p->h[i].num==0)//若遇到未使用的位置则调整结束
143 {
144 printf("联系人已经删除!\n");
145 return 1;
146 }
147 r=p->h[i].num%50;//r为i位置中的元素未发生碰撞应在位置
148 ///
149 //若r位于空位和当前位置i之间,则说明该元素不受影响,则跳出寻找下一个
150 if(j
151 continue;
152 if(j>i && j
153 continue;
154 if(j>i && r<=i)
155 continue;
156 //以上3条语句保证了r位于i与j之间
157
158 break;
159 }
160 p->h[j]=p->h[i];//将选择的元素赋值到空位
161 }
162
163
164
165 }
166 else {printf("不存在该人!\n");}
167 return 1;
168 }
169
170
171 /删除联系人/
172
173
174
175
176 int list(phash p){
177 int i;
178 for(i=0;i<50;i++){
179 if(p->h[i].num!=0)
180 printf("%d\t%s\t%s\n",p->h[i].num,p->h[i].name,p->h[i].address);
181 }
182 return 1;
183 }
184 ///输出所有联系人//
185
186
187
188 ///
189 int save(phash p){
190 int i;
191 FILE *fout;
192 if((fout=fopen("xinxi.txt","w"))==NULL)//判断文件是否存在
193 {
194 printf("写入文件失败!\n");
195 return 0;
196 }
197 for(i=0;i<50;i++)
198 { if(p->h[i].num != 0)//判断联系人是否存在
199 fprintf(fout,"%d %s %s\n",p->h[i].num,p->h[i].name,p->h[i].address);//输出存在的联系人
200 }
201 fclose(fout);//关闭文件
202 printf("文件已保存\n");
203 return 1;
204 }
205 //保存联系人到指定文件
206
207
208 ///
209 int load(phash p){
210 FILE *fin;
211 Data temp;
212 int i;
213 if((fin=fopen("xinxi.txt","r"))==NULL)//判断文件是否存在
214 {
215 printf("文件读取失败!\n");
216 return 0;
217 }
218 while(!feof(fin))//判断文件是否结束
219 {
220 i=fscanf(fin,"%d %s %s",&temp.num,&temp.name,&temp.address);//读取联系人信息
221 if(i==-1) break;
222 else Append(p,temp);//把读取的信息插入散列表
223 }
224 fclose(fin);
225 printf("文件读取成功\n");
226 return 1;
227 }
228 ///读取指定文件的信息
229
230
231 /
232 int start(phash p){
233 int i;
234 Data st;
235 printf("请输入三名联系人的信息!(电话号码,姓名,地址,空格隔开)\n");
236 for(i=0;i<3;i++)
237 {
238 scanf("%d %s %s",&st.num,&st.name,&st.address);
239 Append(p,st);
240
241 }
242 return 1;
243 }
244 初始化信息
245
246
247 //
248 int newnum(phash p){
249 int num,position;
250 Data n;
251 printf("输入要新建的联系人的号码!\n");
252 scanf("%d",&num);
253 if(find(p,num,&position)==1)//检索联系人是否存在
254 {printf("联系人存在!\n");
255 return 0;
256 }
257 else{
258 n.num=num;
259 printf("请输入需要新建联系人的信息!(姓名 地址,空格隔开)\n");
260 scanf("%s %s",&n.name,&n.address);
261 Append(p,n);
262 printf("新建联系人完成!\n");
263 return 1;
264 }
265 }
266 新建联系人并插入散列表/
267
268
269
270 ///
271 int findnum(phash p){
272 int i,num,position;
273 printf("输入要查询的联系人的号码!\n");
274 scanf("%d",&num);
275 if(find(p,num,&position)==1)
276 {
277 printf("%d\t%s\t%s\n",num,p->h[position].name,p->h[position].address);
278 }
279 else printf("要查找的联系人不存在\n");
280 return 1;
281 }
282 /查找联系人并输出信息//
283
284
285
286 ///
287 int menu(phash p){
288 int i;
289
290 printf("********请输入要进行的操作!*********\n\n0-退出通讯录选单\n1-新建联系人\n2-查找联系人\n3-删除联系人\n4-修改联系人的相关信息\n5-保存通讯录至文件\n6-读取文件中的联系人信息\n7-显示通信录的全部信息\n");
291 scanf("%d",&i);
292
293 switch(i)
294 {
295 case 0: exit(0); break;
296 case 1: newnum(p); break;
297 case 2: findnum(p); break;
298 case 3: Delete(p); break;
299 case 4: alter(p); break;
300 case 5: save(p); break;
301 case 6: load(p); break;
302 case 7: list(p); break;
303 default : printf("选择有误!\n");
304 }
305 return 1;
306 }
307 ///选单///
308
309
310 int main(){
311
312 int i;
313 phash h;
314 h=creat();
315 printf("********************欢迎使用通讯录存储系统**************************\n");
316 printf("* 当联系人信息文件不存在时,请初始化通讯录,存入联系人的相关信息。*\n");
317 printf("* 当联系人信息文件存在时,请读取信息文件。 *\n");
318 printf("* 在执行完所有操作时,请保存文件后退出 *\n");
319 printf("* 可存储号码50个 *\n");
320 printf("* 号码长度为5位 *\n");
321 printf("* 姓名,地址为10个字符 *\n");
322 printf("********************************************************************\n");
323 printf("\n");
324 printf("请选择要进行的操作!1-初始化,2-读取联系人\n");
325 scanf("%d",&i);
326 if(i==1)
327 start(h);
328 else if(i==2)
329 load(h);
330 else
331 printf("输入错误!\n");
332 for(;;)
333 {
334 menu(h);
335 }
336 return 1;
337 }