数据结构实验散列表.docx
《数据结构实验散列表.docx》由会员分享,可在线阅读,更多相关《数据结构实验散列表.docx(19页珍藏版)》请在冰豆网上搜索。
数据结构实验散列表
计算机科学与技术系
哈希表的设计与实现项目报告
专业名称计算机科学与技术
项目课程数据结构与算法
项目名称哈希表的设计与实现
班级
项目人员钱海峰,郑秀娟,王传敏,杨青,凌波
实验日期2015.12.9
目录
一.设计目的…………………………………………………………3
二.问题分析…………………………………………………………3
三.设计环境…………………………………………………………3
四.人员分配…………………………………………………………3
五.详细设计和编码…………………………………………………4
六.实验分析…………………………………………………………7
1测试分析……………………………………………………7
2性能分析……………………………………………………11
附录……………………………………………………………………12
参考书目………………………………………………………………17
一.设计目的
(1)掌握散列结构和散列函数的相关概念
(2)掌握散列结构的存储结构的相关概念
(2)掌握散列冲突的处理方法
(3)运用散列解决冲突问题。
二.问题分析
要完成如下要求:
设计哈希表实现整数查询系统。
实现本项目需要解决以下问题:
(1)如何设计一个哈希表。
(2)如何在哈希表中插入记录。
(3)如何删除哈希表中的记录。
(4)如何查找并显示记录。
(5)如何解决冲突问题。
三.设计环境
⒈硬件:
计算机每人一台。
⒉软件:
Windows操作系统和MicrosoftVisualVC++6.0编译器。
四.人员分配
负责人
负责内容
钱海峰
showHashTable(),menu()
郑秀娟
insert(),search()
王传敏
Sanlibiao.h,main.c,项目文档
杨青
Hash(),createHashTable()
凌波
dele(),initHashTable()
五.详细设计和编码
1.定义结点结构类型
在链地址法中,每个结点对应一个链表结点,由3个域组成,结构如图9-1所示。
其中,key为关键字域,存放结点关键字;data为数据域,存放结点数据信息;next为链域,存放指向下一个同义词结点的指针。
Key
data
next
图9-1链地址法结点结构
链地址数据结构类型如下:
#defineMAX_LENGTH50
typedefstructnode{
intdata;
structnode*next;
}ElemNode;
typedefstruct{
ElemNode*first;
}ElemHeader,HashTable[MAX_LENGTH];#include
2.对哈希函数的定义
设计一个Hash()函数,本设计中对散列函数选择的是除留余数法,即对关键字进行模运算,将运算结果所得的余数作为关键字(或结点)的存储地址,即i=htmodn,本设计n由用户自己输入,然后将计算出来的结果返回。
具体设计如下:
intHash(intht)
{inti;
i=ht%n;
returni;
}
3.初始化散列链表
初始化链地址散列算法只需要把散列表中所有表头结点的指针域置为NULL。
初始化散列链表的算法如下:
voidinitHashTable(HashTableht,intn)
{
inti;
for(i=0;i}
4.创建哈希表
在整个设计中,创建哈希表必须是第一步要做的,结点之前应先输入结点的个数,利用链地址法解决冲突。
添加结点实际是调用了插入结点函数insert(),需要利用哈希函数计算出地址,其次将结点插入以关键字为地址的链表后。
建立结点应包括动态申请内存空间,想地址中输入信息,同时最后一个结点中的next指针等于NULL。
具体实现如下:
intcreateHashTable(HashTableht)
{
HashTable*p=ht;
intad[MAX_LENGTH]={0};
inti;
printf("请输入插入个数n:
");
scanf("%d",&n);
printf("\n请输入插入%d个整数:
",n);
for(i=0;iscanf("%d",&ad[i]);
initHashTable(p,n);
for(i=0;iinsert(p,ad[i]);
return1;
5.散列链表插入结点算法
将一个结点插入到散列链表中,其算法分为以下几步:
(1)根据结点关键字计算散列地址;
(2)根据散列地址找到表头结点,并将结点插入到对应的链表中。
链地址法散列表的插入算法如下:
voidinsert(HashTableht,intele)
{
inti;
ElemNode*p;
i=Hash(ele);
p=(ElemNode*)malloc(sizeof(ElemNode));
p->data=ele;
p->next=ht[i].first;
ht[i].first=p;
}
6.散列链表查找结点算法
在散列链表中查找一个结点,其算法分为以下几步:
(1)根据待查找关键字计算散列地址;
(2)在散列地址所指向的单链表中顺序查找待查找关键字;
(3)如果找到待查关键字,则返回指向该结点的指针;否则返回NULL。
散列链表中查找结点的算法如下:
ElemNode*search(HashTableht,intele)
{inti;
ElemNode*p;
i=Hash(ele);
p=ht[i].first;
while(p!
=NULL&&p->data!
=ele){p=p->next;}
if(p!
=NULL)
{printf("数据%d的位置为%d\n",ele,i);
returnp;
}
else
{printf("哈希表中无%d\n",ele);
returnp;
}
}
7.散列链表删除结点算法
在散列表中删除一个结点,其算法分为两步:
(1)查找要删除的结点;
(2)如果找到则删除,否则显示提示信息。
在散列表中删除一个结点的算法如下:
voiddele(HashTableht,intele){//删除指定数据
inti;
ElemNode*p,*q;
i=Hash(ele);
p=ht[i].first;
if(p==NULL){
printf("erroroccurred!
");
}
if(p->data==ele){
ht[i].first=p->next;
}
else{
q=p->next;
while(q!
=NULL&&q->data!
=ele){
p=q;
q=q->next;
}
if(q==NULL){
printf("erroroccurred!
");
}
else{
p->next=q->next;
free(q);
}
}
}
六.实验分析
1.测试分析
(1)建立哈希表
(2)插入一个结点并显示:
(3)查找结点:
在哈希表中没有3这个数,会输出一行提示信息。
(4)删除一个结点并显示:
2.性能分析
散列法本质上是一种通过关键字直接计算存储地址的方法。
在理想情况下,散列函数可以把结点均匀地分布在散列表中,不发生冲突,则查找过程无需比较,其时间复杂度O
(1)。
但在实际使用过程中,为了将范围广泛的关键字映射到一组连续的存储空间,往往会发生同义词冲突,这时就需要进行关键字比较。
能够把关键字尽可能均匀地分布到散列表中的函数是“好”的散列函数。
好的散列函数可以有效地降低冲突的的发生,从而提高查找性能。
但好的散列函数和关键字的数字特征有关,因此不存在对任何结点都好的散列函数。
对于同一种散列函数,采用不同的冲突处理方法将产生不同的效果,例如线性探测法容易导致“二次聚集”,而拉链法可以从根本上杜绝二次聚集,从而提高查找性能。
不过也会“浪费”一部分散列表的空间。
附录
****************************程序源代码*********************************
//头文件sanlibiao.h
#include
#include
#defineMAX_LENGTH50
typedefstructnode{
intdata;
structnode*next;
}ElemNode;
typedefstruct{
ElemNode*first;
}ElemHeader,HashTable[MAX_LENGTH];
intn;//存储哈希表长度
voidinitHashTable(HashTableht,intn);
voidinsert(HashTableht,intele);
ElemNode*search(HashTableht,intele);
voiddele(HashTableht,intele);
intHash(intht);
intcreateHashTable(HashTableht);
voidshowHashTable(HashTableht);
voidmenu(HashTableht);//菜单
//功能函数sanlibiao.c
#include"sanlibiao.h"
voidinitHashTable(HashTableht,intn){//初始化
inti;
for(i=0;iht[i].first=NULL;
}
}
voidinsert(HashTableht,intele){//插入
inti;
ElemNode*p;
i=Hash(ele);
p=(ElemNode*)malloc(sizeof(ElemNode));
//p->key=ele;
p->data=ele;
p->next=ht[i].first;
ht[i].first=p;
}
ElemNode*search(HashTableht,intele){//查找
inti;
ElemNode*p;
i=Hash(ele);
p=ht[i].first;
while(p!
=NULL&&p->data!
=ele){
p=p->next;
}
if(p!
=NULL)
{
printf("数据%d的位置为%d\n",ele,i);
returnp;
}
else
{
printf("哈希表中无%d\n",ele);
returnp;
}
}
voiddele(HashTableht,intele){//删除指定数据
inti;
ElemNode*p,*q;
i=Hash(ele);
p=ht[i].first;
if(p==NULL){
printf("erroroccurred!
");
}
if(p->data==ele){
ht[i].first=p->next;
}
else{
q=p->next;
while(q!
=NULL&&q->data!
=ele){
p=q;
q=q->next;
}
if(q==NULL){
printf("erroroccurred!
");
}
else{
p->next=q->next;
free(q);
}
}
}
intHash(intht){//哈希函数
inti;
i=ht%n;
returni;
}
intcreateHashTable(HashTableht)//创建哈希表
{
HashTable*p=ht;
intad[MAX_LENGTH]={0};
inti;
printf("请输入插入个数n:
");
scanf("%d",&n);
printf("\n请输入插入%d个整数:
",n);
for(i=0;iscanf("%d",&ad[i]);
initHashTable(p,n);
for(i=0;iinsert(p,ad[i]);
return1;
}
voidshowHashTable(HashTableht)//显示哈希表
{
inti;
ElemNode*p;
//i=Hash(ele);
for(i=0;i{
p=ht[i].first;
if(p!
=NULL)printf("位置%d上的数据:
",i);
while(p!
=NULL)
{
printf("%d",p->data);
p=p->next;
}
if(ht[i].first!
=NULL)printf("\n");
}
}
voidmenu(HashTableht)
{
intp,h;//p菜单选择;
do
{
//system("cls");//清屏
printf("★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆\n");
printf("☆★☆★\n");
printf("★☆**************欢迎来到哈希表系统!
***************★☆\n");
printf("☆★合肥学院☆★\n");
printf("★☆计算机科学与技术★☆\n");
printf("☆★钱海峰,郑秀娟,王传敏,杨青,凌波☆★\n");
printf("☆★☆★\n");
printf("☆★※※※※※※※☆★\n");
printf("★☆※菜单※★☆\n");
printf("☆★※※※※※※※☆★\n");
printf("☆★☆★\n");
printf("★☆**************
(1)---创建哈希表******************★☆\n");
printf("☆★**************
(2)---查找******************★☆\n");
printf("★☆**************(3)---删除******************★☆\n");
printf("☆★**************(4)---插入******************★☆\n");
printf("★☆**************(5)---输出哈希表******************★☆\n");
printf("☆★**************(0)---退出******************☆★\n");
printf("★☆****************************************************★☆\n");
printf("☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★\n");
printf("\n请在上述序号中选择一个并输入:
");
scanf("%d",&p);
switch(p)
{
case1:
createHashTable(ht);break;
case2:
printf("请输入要查找的数:
\n");scanf("%d",&h);search(ht,h);break;
case3:
printf("请输入要删除的数:
\n");scanf("%d",&h);dele(ht,h);printf("\n");break;
case4:
printf("请输入要插入的数:
\n");scanf("%d",&h);insert(ht,h);printf("\n");break;
case5:
showHashTable(ht);printf("\n");break;
case0:
break;//退出
default:
printf("输入错误!
请重新输入!
\n");break;
}
//system("pause");//系统暂停,提示按任意键继续。
。
。
。
}while(p!
=0);//fordo
}
//主函数mian.c
#include"sanlibiao.h"
intmain(){
HashTableht;
menu(ht);//进入菜单循环
return0;
参考书目
王昆仑,李红,《数据结构与算法》,中国铁道出版社,2007年6月第一版。
谭浩强,《C语言程序设计》,北京:
清华大学出版社,2005年7月第三版。