转载自https://blog.csdn.net/wendy_dreamcatcher/article/details/72860935
题目要求是这个样子的。。。
设计散列表(哈希表)实现电话号码查找系统。
基本要求:
1) 设每个记录有下列数据项:电话号码、用户名、地址等相关信息;
2) 从键盘输入各记录,分别以电话号码和用户名为关键字建立散列表;
3) 采用一定的方法解决冲突;
4) 查找并显示给定电话号码的记录;
5) 查找并显示给定用户名的记录。
6) 允许对记录进行相关的增加,修改,删除,。
扩展要求:
1) 系统功能的完善;
2) 设计不同的散列函数,比较冲突率;
3) 在散列函数确定的前提下,尝试各种不同类型处理冲突的方法,考察平均查找长度的变化。
其实。。。
我到现在也没有弄明白为什么要分别以电话号码和用户名来建立哈希表呢。。。
搞不明白。。。
- #include<stdio.h>
- #include<stdlib.h>
- #include<string.h>
- #define MAXSIZE 20
- #define MAX_SIZE 20 //人名的最大长度
- #define HASHSIZE 60 //定义表长
- #define SUCCESS 1
- #define UNSUCCESS -1
- #include<iostream>
- using namespace std;
- typedef int Status; //为现有类型添加一个同义字
- typedef char NA[MAX_SIZE];// typedef 掩饰数组类型
- typedef struct//记录
- {
- NA name;
- NA address; //关键字
- NA tel;
- }humen; //查找表中记录类型
- typedef struct //建立哈希表
- {
- humen *elem[HASHSIZE];//数据元素存储基址
- int cou; //当前数据元素个数
- int siz; //当前容量
- }HashTable;
- typedef struct //建立哈希表
- {
- humen *elema[HASHSIZE];//数据元素存储基址
- int cou2; //当前数据元素个数
- int siz2; //当前容量
- }Hashtable;
- Status eq(char x[MAX_SIZE],char y[MAX_SIZE]) //比较两个数组是否相等,若相等返回1,否则返回-1
- {
- if(strcmp(x,y)==0)
- return 1;
- else return -1;
- }
- Status NUM_BER; //记录的个数 全局变量
- Status NUM_BER1; //记录的个数 全局变量
- void output(humen* a) //遍历用户的信息
- {
- int i;
- system("cls");
- printf("姓名\t地址\t电话号码");
- for( i=0;i<NUM_BER+NUM_BER1;i++)
- {
- if(!a[i].name[0]=='\0')
- printf("\n%s\t%s\t\t%s",a[i].name,a[i].address,a[i].tel);
- }
- cout<<endl;
- system("pause");
- system("CLS");
- }
- int Hash(char name[MAX_SIZE])//将输入的字符数组转换成ASCII码后相加求和,然后取表长余数,并将余数值返回//一次探测
- {
- int i,m;
- i = 1;
- m=(int)name[0]; //强制转化成数字
- while(name[i]!='\0')
- {
- m+=(int)name[i];//余数
- i++;
- }
- m=m%HASHSIZE;
- return m;
- }
- int Hash2(char num[MAXSIZE])
- {
- int i=0,key=0;
- while(i!=MAXSIZE)//关键字
- {
- key+=(num[i]-'0');//关键字求和
- i++;
- }
- key=key%HASHSIZE;
- return key;
- }
- Status collision(int p,int c)//冲突处理函数,采用二次探测法解决冲突//二次探测
- {
- int i,q;
- i=c/2+1;
- while(i<HASHSIZE)
- {
- if(c%2==0)
- {
- c++;
- q=(p+i*i)%HASHSIZE;//倘若c为偶数,函数公式为:(余数+i*i)%表长,返回合理值
- if(q>=0)
- return q;
- else
- i=c/2+1;
- }
- else
- {
- q=(p-i*i)%HASHSIZE;//若c为奇数,函数公式为:(余数-i*i)%表长,返回合理值
- c++;
- if(q>=0) return q;
- else i=c/2+1;
- }
- }
- return UNSUCCESS;
- }
- void CreateHash(HashTable* H,humen* a,int m)//建表,以人的姓名为关键字,建立相应的哈希表
- {
- int i,p=-1,c=0,pp;
- cout<<"以姓名为关键字建立哈希表"<<endl;
- for(i=0;i<m;i++)
- {
- c=0; //记录冲突次数的变量
- p=Hash(a[i].name);
- pp=p;
- while(H->elem[pp]!=NULL) //若不为空,即产生冲突,调用冲突处理函数
- {
- pp=collision(p,c); //若哈希地址冲突,进行冲突处理
- c++;
- if(pp<0)
- {
- printf("第%d记录无法解决冲突",i+1);//需要显示冲突次数时输出
- continue; //无法解决冲突,跳入下一循环
- }
- }
- H->elem[pp]=&(a[i]); //求得哈希地址,将信息存入
- H->cou++; //表当前数据个数+1
- printf("第%d个记录冲突次数为%d。\n",i+1,c);
- }
- }
- void CreateHash2(Hashtable* H,humen* a,int m) //建表,以人的姓名为关键字,建立相应的哈希表
- {
- int i,p=-1,c=0,pp;
- cout<<"以电话号码为关键字建立哈希表"<<endl;
- for(i=0;i<m;i++)
- {
- c=0; //记录冲突次数的变量
- p=Hash2(a[i].tel);
- pp=p;
- while(H->elema[pp]!=NULL) //若不为空,即产生冲突,调用冲突处理函数
- {
- pp=collision(p,c); //若哈希地址冲突,进行冲突处理
- c++;
- if(pp<0)
- {
- printf("第%d记录无法解决冲突",i+1); //需要显示冲突次数时输出
- continue; //无法解决冲突,跳入下一循环
- }
- }
- H->elema[pp]=&(a[i]); //求得哈希地址,将信息存入
- H->cou2++; //表当前数据个数+1
- printf("第%d个记录冲突次数为%d。\n",i+1,c);
- }
- }
- void Create(HashTable* H,humen* a,Hashtable* H2) //创建新的通讯录
- {
- system("CLS");//调用DOS命令CLS能够清屏
- memset(a->tel,0,sizeof(a->tel));
- printf("\n输入要添加的个数:\n");
- scanf("%d",&NUM_BER);
- for(int i=0;i<NUM_BER;i++) //输入创建的用户信息
- {
- printf("请输入第%d个记录的姓名:\n",i+1);
- scanf("%s",a[i].name);
- printf("请输入%d个记录的地址:\n",i+1);
- scanf("%s",a[i].address);
- printf("请输入第%d个记录的电话号码:\n",i+1);
- scanf("%s",a[i].tel);
- }
- printf("添加成功!!!\n");
- CreateHash(H,a,NUM_BER);
- CreateHash2(H2,a,NUM_BER);
- system("pause");
- system("CLS");
- }
- void add(humen* a,humen *b,HashTable* H,Hashtable* H2) //增加新的通讯录
- {
- memset(b->tel,0,sizeof(b->tel));
- system("CLS"); //调用DOS命令CLS能够清屏
- printf("\n输入要添加的个数:\n");
- scanf("%d",&NUM_BER1);
- for(int i=0;i<NUM_BER1;i++) //输入创建的用户信息
- {
- printf("请输入第%d个记录的姓名:",i+1);
- scanf("%s",b[i].name);
- for(int j=0;j<MAXSIZE;j++)
- {
- a[i+NUM_BER].name[j]=b[i].name[j];
- }
- printf("请输入%d个记录的地址:",i+1);
- scanf("%s",b[i].address);
- for(int j=0;j<MAXSIZE;j++)
- {
- a[i+NUM_BER].address[j]=b[i].address[j];
- }
- printf("请输入第%d个记录的电话号码:",i+1);
- scanf("%s",b[i].tel);
- for(int j=0;j<MAXSIZE;j++)
- {
- a[i+NUM_BER].tel[j]=b[i].tel[j];
- }
- }
- printf("添加成功!!!\n");
- CreateHash2(H2,b,NUM_BER1);
- CreateHash(H,b,NUM_BER1);
- system("pause");
- system("CLS");
- }
- void SearchHash(HashTable* H,int c,humen *a,Hashtable* H2) //在通讯录里查找姓名关键字,c用来记录冲突次数,若查找成功,显示信息
- {
- int i;
- int p,pp;
- NA NAME; //定义要查找的名字的字符数组
- system("cls");
- int l;
- cout<<"1.按姓名查找"<<endl;
- cout<<"2.按电话号码查找"<<endl;
- cout<<"请输入你的选项"<<endl;
- cin>>l;
- switch(l)
- {
- case 1:
- do
- {
- printf("\n请输入要查找记录的姓名:\n");
- scanf("%s",NAME);
- p=Hash(NAME); //调用一次探测函数
- pp=p;
- while((H->elem[pp]!=NULL)&&(eq(NAME,H->elem[pp]->name)==-1))//倘若一探测结果和所要查找的结果不同,调用二次探测函数
- {
- pp=collision(p,c);
- c++; //冲突次数增加
- }
- if(H->elem[pp]!=NULL&&eq(NAME,H->elem[pp]->name)==1) //探测到结果后将信息输出
- {
- printf("\n查找成功!\n查找过程冲突次数为%d.以下是您需要要查找的信息:\n\n",c);
- printf("姓名:%s\n地址:%s\n电话号码:%s\n",H->elem[pp]->name,H->elem[pp]->address,H->elem[pp]->tel);
- }
- else printf("\n此人不存在,查找不成功!\n");
- cout<<"是否继续查找?1.继续0.退出"<<endl;
- cin>>i;
- }while(i!=0);
- system("pause");
- system("CLS");
- break;
- case 2:
- do
- {
- memset(NAME,0,sizeof(NAME));//初始化
- printf("\n请输入要查找记录的电话号码:\n");
- scanf("%s",NAME);
- p=Hash2(NAME); //调用一次探测函数
- pp=p;
- while((H2->elema[pp]!=NULL)&&(eq(NAME,H2->elema[pp]->tel)==-1))//倘若一探测结果和所要查找的结果不同,调用二次探测函数
- {
- pp=collision(p,c);
- c++; //冲突次数增加
- }
- if(H2->elema[pp]!=NULL&&eq(NAME,H2->elema[pp]->tel)==1) //探测到结果后将信息输出
- {
- printf("\n查找成功!\n查找过程冲突次数为%d.以下是您需要要查找的信息:\n\n",c);
- printf("姓名:%s\n地址:%s\n电话号码:%s\n",H2->elema[pp]->name,H2->elema[pp]->address,H2->elema[pp]->tel);
- }
- else printf("\n此人不存在,查找不成功!\n");
- cout<<"是否继续查找?1.继续0.退出"<<endl;
- cin>>i;
- }while(i!=0);
- system("CLS");
- break;
- default:
- break;
- }
- }
- void Modify(HashTable *H,int c,humen* a)//在通讯录里修改某人信息
- {
- int p,pp;
- NA NAME; //想要修改的姓名数组
- system("cls");
- cout<<"输入你所要修改的原用户名"<<endl;
- scanf("%s",NAME);
- p=Hash(NAME); //调用一次探测函数
- pp=p;
- while((H->elem[pp]!=NULL)&&(eq(NAME,H->elem[pp]->name)==-1)) //倘若一探测结果和所要查找的结果不同,调用二次探测函数
- pp=collision(p,c);
- if(H->elem[pp]!=NULL&&eq(NAME,H->elem[pp]->name)==1) //探测到结果后修改信息
- {
- int m;
- do
- {
- cout<<"修改信息"<<endl;
- cout<<"1.修改姓名"<<endl;
- cout<<"2.修改地址"<<endl;
- cout<<"3.修改电话号码"<<endl;
- cout<<"请选择你想要选择的选项,输入0结束修改此用户信息"<<endl;
- cin>>m;
- if(m==1)
- {
- int p,n=0,m,i;
- printf("请输入修改后记录的姓名:\n");
- scanf("%s",H->elem[pp]->name);
- NA t;
- for(int i=0;i<MAXSIZE;i++)
- {
- t[i]=H->elem[pp]->name[i];
- }
- p=Hash(t);
- m=p;
- while(H->elem[m]!=NULL)//若不为空,即产生冲突,调用冲突处理函数
- {
- m=collision(p,n); //若哈希地址冲突,进行冲突处理
- n++;
- if(m<0)
- {
- cout<<"冲突无法解决"<<endl;
- break;
- }
- }
- H->elem[m]=H->elem[pp]; //求得哈希地址,将信息存入
- }
- if(m==2)
- {
- printf("请输入修改后记录的地址:\n");
- scanf("%s",H->elem[pp]->address);
- }
- if(m==3)
- {
- printf("请输入修改后记录的电话号码:\n");
- scanf("%s",H->elem[pp]->tel);
- }
- }while(m!=0);
- printf("修改成功!\n");
- }
- else
- printf("此人不存在,修改不成功!\n");
- system("CLS");
- }
- void Delete(HashTable* H,int c,humen* a) //在通讯录里查找姓名关键字,若查找成功,显示信息然后删除
- {
- int i;
- do
- {
- int m,p,pp;
- NA NAME;
- m=0;
- system("cls");
- printf("请输入要删除记录的姓名:\n");
- m++;
- scanf("%s",NAME);//输入想要删除的记录的名字
- p=Hash(NAME);
- pp=p;
- while((H->elem[pp]!=NULL)&&(eq(NAME,H->elem[pp]->name)==-1))//倘若一探测结果和所要查找的结果不同,调用二次探测函数
- pp=collision(p,c);
- if(H->elem[pp]!=NULL&&eq(NAME,H->elem[pp]->name)==1)//探测到结果后删除信息
- {
- printf("以下是您需要要删除的信息:\n\n",c);
- printf("姓名:%s\n地址:%s\n电话号码:%s\n",H->elem[pp]->name,H->elem[pp]->address,H->elem[pp]->tel);
- for(int i=0;i<NUM_BER+NUM_BER1;i++)
- {
- if(eq(NAME,a[i].name)==1)
- {
- a[i].name[0]='\0';
- }
- }
- H->elem[pp]->name[0]='\0';//将所要删的用户的电话号码清空
- H->elem[pp]->address[0]='\0';
- H->elem[pp]->tel[0]='\0';
- cout<<"1"<<H->elem[pp]->name[0]<<"1"<<endl;
- printf("删除成功!!!\n");
- }
- else
- printf("此人不存在,删除不成功!\n");
- cout<<"是否继续删除?1.继续0.退出"<<endl;
- cin>>i;
- }while(i!=0);
- system("CLS");
- }
- int main()
- {
- int c,i=0;
- humen a[MAXSIZE];//结构体数组变量
- humen b[MAXSIZE];
- HashTable *H;//哈希表指针变量
- Hashtable *H2;
- H2=(Hashtable*)malloc(sizeof(Hashtable));//申请空间
- for(i=0;i<HASHSIZE;i++)//初始化哈希表
- {
- H2->elema[i]=NULL;
- H2->siz2=HASHSIZE;
- H2->cou2=0;
- }
- H=(HashTable*)malloc(sizeof(HashTable));//申请空间
- for(i=0;i<HASHSIZE;i++) //初始化哈希表
- {
- H->elem[i]=NULL;
- H->siz=HASHSIZE;
- H->cou=0;
- }
- while (1)//菜单目录
- {
- int num;
- printf("***************************通讯录****************************");
- printf("\n* 【1】. 创建用户信息 *");
- printf("\n* 【2】. 添加用户信息 *");
- printf("\n* 【3】. 显示所有用户信息 *");
- printf("\n* 【4】. 查找用户信息 *");
- printf("\n* 【5】. 删除用户信息 *");
- printf("\n* 【6】. 修改用户信息 *");
- printf("\n* 【7】. 退出程序 *");
- printf("\n*****************************************************************");
- printf("\n");
- printf("\n请输入一个任务选项>>>");
- printf("\n");
- scanf("%d",&num);
- switch(num)
- {
- case 1:
- Create(H,a,H2) ;
- break;
- case 2:
- add(a,b,H,H2) ;
- break;
- case 3:
- output(a);
- break;
- case 4:
- c=0;
- SearchHash(H,c,a,H2);
- break;
- case 5:
- c=0;
- Delete(H,c,a);
- break;
- case 6:
- c=0;
- Modify(H,c,a);
- break;
- case 7:
- return 0;
- break;
- default:
- printf("输入错误,请重新输入!");
- printf("\n");
- }
- }
- system("pause");
- return 0;
- }