您的位置:首页 > 理论基础 > 数据结构算法

【数据结构】通讯录查询系统的设计与实现(散列表(哈希表))

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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐