【数据结构】通讯录查询系统的设计与实现(散列表(哈希表))
2017-06-26 21:14
351 查看
1.问题描述:
为某个单位建立一个员工通讯录管理系统,可以方便查询每一个员工的电话与地址。设计散列表存储,设计并实现通讯录查找系统。
2.基本要求
(1)每个记录有下列数据项:电话号码、用户名、地址;
(2)从键盘输入各记录,分别以电话号码为关键字建立散列表;
(3)采用二次探测再散列法解决冲突;
(4)查找并显示给定电话号码的记录;
(5)通讯录信息文件保存。
3 . 原理
1.哈希表是根据关键码值而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希表,函数f(key)为哈希函数。
2. 二次探测再散列法:若发生冲突,则按照+1²,-1²,+2²,-2²…方式进行探测再散列的方法。
4 . 思路
此题基本上可以说就是哈希表的简单应用:
① 构建哈希表(需要构造一个哈希函数,确定一个合适的处理冲突的方法)
② 按照电话号码查找并输出
③ 将哈希表按序存进文件Output中
5 . 代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define MAXSIZE 50
using namespace std;
int Czy=1;
typedef struct record
{
char Number[20];
char Name[20];
char Address[20];
}Record;
typedef struct Hash
{
Record *data;
int cnt;
int size;
}*HashTable,HashElem;
//哈希函数,将电话号码每一位求和
int GetHashKey(char ar[])
{
int len=strlen(ar);
int key=0;
for(int i=0;i<len;i++){
key+=ar[i]-'0';
}
return key%MAXSIZE;//必须取模,否则下标越界
}
//冲突处理,二次探测再散列
int HandleCollision(HashTable table,int key)
{
Czy=1; //从2,3,4,5,.......
while(1){
Czy++; //从2,3,4,5,.......
if(Czy%2==0) {
if(table->data[(key+(Czy/2)*(Czy/2))%MAXSIZE].Name[0]==0)
return (key+(Czy/2)*(Czy/2))%MAXSIZE;
}
else if(Czy%2!=0) {
if((key-(Czy/2)*(Czy/2))<0) continue;//由于是减法,要注意负数不能取模
if(table->data[(key-(Czy/2)*(Czy/2))%MAXSIZE].Name[0]==0)
return (key-(Czy/2)*(Czy/2))%MAXSIZE;
}
}
//return -1;
}
//构建哈希表
void CreateHashTable(HashTable &table,Record *record,int n)
{
int key;
for(int i=0;i<n;i++){
key=GetHashKey(record[i].Number);
if(table->data[key].Name[0]!=0)
key=HandleCollision(table,key);
strcpy(table->data[key].Number,record[i].Number);
strcpy(table->data[key].Name,record[i].Name);
strcpy(table->data[key].Address,record[i].Address);
}
}
//按照电话号码寻找
int SerchKey(HashTable table,char PhoneNumber[])
{
int key=GetHashKey(PhoneNumber);
if(strcmp(table->data[key].Number,PhoneNumber)){
for(Czy=1;Czy<MAXSIZE;Czy++){
if(Czy%2==0) {
if(!strcmp(PhoneNumber,table->data[(key+(Czy/2)*(Czy/2))%MAXSIZE].Number)){
key= (key+(Czy/2)*(Czy/2))%MAXSIZE;
break;
}
}
else if(Czy%2!=0) {
if((key-(Czy/2)*(Czy/2))<0) continue;//由于是减法,要注意负数不能取模
if(!strcmp(PhoneNumber,table->data[(key-(Czy/2)*(Czy/2))%MAXSIZE].Number)){
key= (key-(Czy/2)*(Czy/2))%MAXSIZE;
break;
}
}
}
}
//if(flag) cout<<"未找到!请重新输入!"<<endl;
cout<<table->data[key].Name<<" "<<table->data[key].Number<<" "<<table->data[key].Address<<endl;
}
//将哈希表存入文件中
void GoToFile(HashTable table)
{
FILE *fp=fopen("Output.txt","w");
for(int i=0;i<=MAXSIZE;i++)
if(table->data[i].Name[0]!=0)
fprintf(fp,"%s %s %s\n",table->data[i].Name,table->data[i].Number,table->data[i].Address);
//printf("%s %s %s\n",table->data[i].Name,table->data[i].Number,table->data[i].Address);
fclose(fp);
}
int main(){
//定义及初始化
Record record[50];
HashElem table;
HashTable numbertable;
numbertable = & table;
numbertable->data=(Record*)malloc(sizeof(record[0])*MAXSIZE);
memset(numbertable->data,0,sizeof(record[0])*MAXSIZE);
numbertable->size=MAXSIZE;
numbertable->cnt=0;
int k;
//输入数据 组数及 各个数据
//freopen("Data.txt","r",stdin);
cin>>k;
for(int i=0;i<k;i++)
cin>>record[i].Number>>record[i].Name>>record[i].Address;
//创建哈希表
CreateHashTable(numbertable,record,k);
//存入文件中
GoToFile(numbertable);
//输入并寻找PhoneNumber(必须存在表中)
char PhoneNumber[20];
cin>>PhoneNumber;
cout<<"给定电话号码为:"<<endl<<PhoneNumber<<endl<<"搜索到的号码数据为:"<<endl;
SerchKey(numbertable,PhoneNumber);
return 0;
}
/*
DATA
7
17718881666 chen hunan
12837192867 yuan hubei
18998239899 duan loudi
13689721388 qian hefei
19999999999 zhang beijing
12673678523 liu liuan
13876352729 luo fujian
*/
5.注:
1.哈希函数求出key时,必须取模MAXSIZE,否则key有可能使数组越界!
2.二次探测再散列的时候只定义一个变量Czy即可,既可以区分奇偶(用于区分正负),也可以算出移动大小(+x²,-x²)
3.只有正数能取模%,因此必须加特判if((key-(Czy/2)*(Czy/2))<0)
为某个单位建立一个员工通讯录管理系统,可以方便查询每一个员工的电话与地址。设计散列表存储,设计并实现通讯录查找系统。
2.基本要求
(1)每个记录有下列数据项:电话号码、用户名、地址;
(2)从键盘输入各记录,分别以电话号码为关键字建立散列表;
(3)采用二次探测再散列法解决冲突;
(4)查找并显示给定电话号码的记录;
(5)通讯录信息文件保存。
3 . 原理
1.哈希表是根据关键码值而直接进行访问的数据结构。也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度。这个映射函数叫做散列函数,存放记录的数组叫做散列表。
给定表M,存在函数f(key),对任意给定的关键字值key,代入函数后若能得到包含该关键字的记录在表中的地址,则称表M为哈希表,函数f(key)为哈希函数。
2. 二次探测再散列法:若发生冲突,则按照+1²,-1²,+2²,-2²…方式进行探测再散列的方法。
4 . 思路
此题基本上可以说就是哈希表的简单应用:
① 构建哈希表(需要构造一个哈希函数,确定一个合适的处理冲突的方法)
② 按照电话号码查找并输出
③ 将哈希表按序存进文件Output中
5 . 代码
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#define MAXSIZE 50
using namespace std;
int Czy=1;
typedef struct record
{
char Number[20];
char Name[20];
char Address[20];
}Record;
typedef struct Hash
{
Record *data;
int cnt;
int size;
}*HashTable,HashElem;
//哈希函数,将电话号码每一位求和
int GetHashKey(char ar[])
{
int len=strlen(ar);
int key=0;
for(int i=0;i<len;i++){
key+=ar[i]-'0';
}
return key%MAXSIZE;//必须取模,否则下标越界
}
//冲突处理,二次探测再散列
int HandleCollision(HashTable table,int key)
{
Czy=1; //从2,3,4,5,.......
while(1){
Czy++; //从2,3,4,5,.......
if(Czy%2==0) {
if(table->data[(key+(Czy/2)*(Czy/2))%MAXSIZE].Name[0]==0)
return (key+(Czy/2)*(Czy/2))%MAXSIZE;
}
else if(Czy%2!=0) {
if((key-(Czy/2)*(Czy/2))<0) continue;//由于是减法,要注意负数不能取模
if(table->data[(key-(Czy/2)*(Czy/2))%MAXSIZE].Name[0]==0)
return (key-(Czy/2)*(Czy/2))%MAXSIZE;
}
}
//return -1;
}
//构建哈希表
void CreateHashTable(HashTable &table,Record *record,int n)
{
int key;
for(int i=0;i<n;i++){
key=GetHashKey(record[i].Number);
if(table->data[key].Name[0]!=0)
key=HandleCollision(table,key);
strcpy(table->data[key].Number,record[i].Number);
strcpy(table->data[key].Name,record[i].Name);
strcpy(table->data[key].Address,record[i].Address);
}
}
//按照电话号码寻找
int SerchKey(HashTable table,char PhoneNumber[])
{
int key=GetHashKey(PhoneNumber);
if(strcmp(table->data[key].Number,PhoneNumber)){
for(Czy=1;Czy<MAXSIZE;Czy++){
if(Czy%2==0) {
if(!strcmp(PhoneNumber,table->data[(key+(Czy/2)*(Czy/2))%MAXSIZE].Number)){
key= (key+(Czy/2)*(Czy/2))%MAXSIZE;
break;
}
}
else if(Czy%2!=0) {
if((key-(Czy/2)*(Czy/2))<0) continue;//由于是减法,要注意负数不能取模
if(!strcmp(PhoneNumber,table->data[(key-(Czy/2)*(Czy/2))%MAXSIZE].Number)){
key= (key-(Czy/2)*(Czy/2))%MAXSIZE;
break;
}
}
}
}
//if(flag) cout<<"未找到!请重新输入!"<<endl;
cout<<table->data[key].Name<<" "<<table->data[key].Number<<" "<<table->data[key].Address<<endl;
}
//将哈希表存入文件中
void GoToFile(HashTable table)
{
FILE *fp=fopen("Output.txt","w");
for(int i=0;i<=MAXSIZE;i++)
if(table->data[i].Name[0]!=0)
fprintf(fp,"%s %s %s\n",table->data[i].Name,table->data[i].Number,table->data[i].Address);
//printf("%s %s %s\n",table->data[i].Name,table->data[i].Number,table->data[i].Address);
fclose(fp);
}
int main(){
//定义及初始化
Record record[50];
HashElem table;
HashTable numbertable;
numbertable = & table;
numbertable->data=(Record*)malloc(sizeof(record[0])*MAXSIZE);
memset(numbertable->data,0,sizeof(record[0])*MAXSIZE);
numbertable->size=MAXSIZE;
numbertable->cnt=0;
int k;
//输入数据 组数及 各个数据
//freopen("Data.txt","r",stdin);
cin>>k;
for(int i=0;i<k;i++)
cin>>record[i].Number>>record[i].Name>>record[i].Address;
//创建哈希表
CreateHashTable(numbertable,record,k);
//存入文件中
GoToFile(numbertable);
//输入并寻找PhoneNumber(必须存在表中)
char PhoneNumber[20];
cin>>PhoneNumber;
cout<<"给定电话号码为:"<<endl<<PhoneNumber<<endl<<"搜索到的号码数据为:"<<endl;
SerchKey(numbertable,PhoneNumber);
return 0;
}
/*
DATA
7
17718881666 chen hunan
12837192867 yuan hubei
18998239899 duan loudi
13689721388 qian hefei
19999999999 zhang beijing
12673678523 liu liuan
13876352729 luo fujian
*/
5.注:
1.哈希函数求出key时,必须取模MAXSIZE,否则key有可能使数组越界!
2.二次探测再散列的时候只定义一个变量Czy即可,既可以区分奇偶(用于区分正负),也可以算出移动大小(+x²,-x²)
3.只有正数能取模%,因此必须加特判if((key-(Czy/2)*(Czy/2))<0)
相关文章推荐
- 如果系统要使用超大整数(超过long长度范围),请你设计一个数据结构来存储这种超大型数字以及设计一种算法来实现超大整数加法运算)
- 模块管理常规功能自定义系统的设计与实现(38--终级阶段 综合查询[5])
- 模块管理常规功能自己定义系统的设计与实现(36--终级阶段 综合查询[3])
- 模块管理常规功能自定义系统的设计与实现(34--终级阶段 综合查询[1])
- 基于HBase的海量数据实时查询系统设计与实现
- 数据结构课设(散列表的设计与实现---电话号码查找系统)
- 数据结构实践课程设计【通讯录管理系统】
- 模块管理常规功能自定义系统的设计与实现(36--终级阶段 综合查询[3])
- 基于java最短路径算法公交查询系统的设计与实现
- 模块管理常规功能自定义系统的设计与实现(35--终级阶段 综合查询[2])
- 公交查询系统的设计与实现
- 模块管理常规功能自定义系统的设计与实现(39--终级阶段 综合查询[6])
- 模块管理常规功能自定义系统的设计与实现(37--终级阶段 综合查询[4])
- 基于J2ME-J2EE的移动工资查询系统 的设计与实现
- 【数据结构】简单哈希表的实现(开散列)
- 个人通讯录管理系统的设计与实现
- 如果系统要使用超大整数(超过long长度范围),请你设计一个数据结构来存储这种超大型数字以及设计一种算法来实现超大整数加法运算
- 设计与实现模块管理系统的基本功能定义自己的(38--终极阶段 综合查询[5])
- 通讯录管理系统设计与实现
- 数据结构课程设计-通讯录管理系统的设计与实现