一、实验名称:散列表的构造和查找
二、实验学时:6学时
三、实验目的
1.理解散列表的存储结构;
2.掌握常用散列函数构造方法和处理冲突方法;
3.在散列表上实现查找的算法。
四、实验内容(步骤)
为小于n个关键字设计一个散列表,使得查找成功时平均查找长度<2.0,要求完成相应的散列表建立和查找。假设关键字为整型数据,散列函数用除留余数法,采用开放定址法的线性探测法处理冲突。
1.从键盘输入关键字个数n及关键字数据;
2.根据输入的关键字个数及平均查找长度要求,设计散列函数和计算表长;
3.构造散列表;
4.在散列表中进行查找。
【实验源代码】
#include<iostream>
#include<cstdlib>
#include<limits.h>
#define INFINITY INT_MAX
using namespace std;
typedef int KeyType;
// 顺序表存储结构
typedef struct
{
KeyType key; // 关键字(数据项)
int time; // 探测次数
}ElemType;
typedef struct
{
ElemType *elem; // 数据元素存储空间基址
int length; // 查找表的长度
}HashTable;
void inputData(KeyType KeyData[],int n)
{
printf("请输入%d个关键字:",n);
for(int i=0;i<n;i++)
{
scanf("%d",&KeyData[i]);
}
}
void initHashTable(HashTable &HT,int m)
{
int i;
HT.elem=(ElemType *)malloc(m*sizeof(ElemType));
HT.length=m;
for(i=0;i<HT.length;i++)
{
HT.elem[i].key=INFINITY; // 赋初值
HT.elem[i].time=0;
}
}
void outputHashTable(HashTable HT)
{
int i,count=0,sum=0;
printf("%8s","地址");
for(i=0;i<HT.length;i++)
printf("%3d",i);
printf("\n");
printf("%8s","关键字");
for(i=0;i<HT.length;i++)
{
if(HT.elem[i].key==INFINITY)
printf("%3s","");
else
printf("%3d",HT.elem[i].key);
}
printf("\n");
printf("%8s","探测次数");
for(i=0;i<HT.length;i++)
{
if(HT.elem[i].time==0)
printf("%3s","");
else
{
printf("%3d",HT.elem[i].time);
count++;
sum+=HT.elem[i].time;
}
}
printf("\n查找成功时的平均查找长度为:%.2f",sum*1.0/count);
}
void calcpm(int n,int &p,int &m)
{
int i,j;
float Snl=2.0; // 平均查找长度
float a; // 装填因子
// 求m
a=1-1/(2*Snl-1);
m=int(n/a)+1;
m=12;
// 求p
p=2;
for(i=m;i>2;i--)
{
for(j=2;j*j<=i;j++)
{
if(i%j==0)
break;
}
if(j*j>i)
{
p=i;
break; // 求得小于m的最大质数
}
}
}
int hashFunc(KeyType key,int p)
{
int addr=-1;
addr=key%p;
return addr;
}
int linearProbing(HashTable HT,int addr,int m,int &time)
{
int i,addri;
for(i=1;i<m;i++)
{
addri=(addr+i)%m;
time++; // 统计探测次数
if(HT.elem[addri].key==INFINITY)
break; // 不冲突
}
return addri;
}
void createHashTable(HashTable &HT,KeyType KeyData[],int n,int p,int m)
{
int i,addr,addri,time;
for(i=0;i<n;i++)
{
time=1;
addr=hashFunc(KeyData[i],p); // 求散列地址
if(HT.elem[addr].key < INFINITY) // 冲突
{
addri=linearProbing(HT,addr,m,time); // 处理冲突
HT.elem[addri].key=KeyData[i];
HT.elem[addri].time=time;
}
else // 不冲突
{
HT.elem[addr].key=KeyData[i];
HT.elem[addr].time=time;
}
}
}
int search(HashTable HT,KeyType key,int p,int m)
{
int i,addr,addri;
addr=hashFunc(key,p); // 求散列地址
if(HT.elem[addr].key==key)
return addr; // 查找成功
else
if(HT.elem[addr].key==INFINITY)
return -1; // 查找失败
else
for(i=1;i<m;i++)
{
addri=(addr+i)%m;
{
if(HT.elem[addri].key==key)
return addri; // 查找成功
else if(HT.elem[addri].key==INFINITY)
return -1; // 查找失败
}
}
return -1;
}
void menu()
{
int i;
system("cls"); // 清屏
printf("\n");
printf("%50s\n","散列表的构造和查找\n");
for(i=0;i<=80;i++)
printf("*");
printf("\n");printf("*") ;
printf(" 1 输入数据 *\n");printf("*") ;
printf(" 2 构造散列函数 *\n");printf("*") ;
printf(" 3 构造散列表 *\n");printf("*") ;
printf(" 4 查看散列表 *\n");printf("*") ;
printf(" 5 散列表查找 *\n");printf("*") ;
printf(" 0 退出 *\n");printf("*") ;
// printf(" \n");
for(i=0;i<80;i++)
printf("*");
printf("\n");
printf("请输入操作序号:");
}
int main()
{
// KeyType 相当于 int
HashTable HT;
KeyType KeyData[50]; // 存放关键字数据
int choice,n,m,p,addr;
KeyType key; // int key
while(1)
{
menu();
scanf("%d",&choice); // 输入你的选择
getchar(); // 接受回车键
switch(choice)
{
case 1:
printf("请输入关键字个数:");
scanf("%d",&n); // 输入关键字
inputData(KeyData,n);
break;
case 2:
calcpm(n,p,m);
printf("p=%d,m=%d\n",p,m);
printf("成功构造散列函数.\n");
break;
case 3:
initHashTable(HT,m);
createHashTable(HT,KeyData,n,p,m);
printf("成功构造散列表.\n");
break;
case 4:
printf("散列表:\n");
outputHashTable(HT);
printf("\n");
break;
case 5:
printf("请输入要查找的关键字:");
scanf("%d",&key);
addr=search(HT,key,p,m);
if(addr!=-1)
printf("关键字%d在散列表中找到,地址为%d.\n",key,addr);
else
printf("关键字%d不在散列表中.\n",key);
break;
case 0:
return 0;
break;
default:
printf("\n输入错误!");
break;
}
system("pause");
}
return 0;
}
【实验运行结果】