《数据结构》课程设计报告
哈希表问题
姓 名 : 郑健
专 业 : 信息管理与信息系统
班 级 : 083221
学 号 : 08322126
指导老师 : 刘自强
设计时间: 20##年5月7日
目录
一,摘要-----------------------------------------------------------------------1
二,设计要求与分析
2.1 课程设计要求-------------------------------------------------------2
2.2 程序分析-------------------------------------------------------------2
三,数据结构选择与概要设计
3.1 数据结构选择-------------------------------------------------------3
3.2 Hash函数流程图---------------------------------------------------4~9
四,设计算法
4.1 建立节点-------------------------------------------------------------10
4.2 哈希函数的定义----------------------------------------------------10
4.3 哈希查找-------------------------------------------------------------11
4.4 程序测试-------------------------------------------------------------11
五,使用说明与测试结果
5.1 使用说明-------------------------------------------------------------11
5.2 主菜单截图----------------------------------------------------------12
5.3 添加记录截图-------------------------------------------------------12
5.4 查找截图-------------------------------------------------------------13
5.5 散列结果截图-------------------------------------------------------13
5.6 清空记录截图-------------------------------------------------------14
六,程序源代码及实验心得
6.1 源代码----------------------------------------------------------------14~18
6.2 实验心得-------------------------------------------------------------19
课程设计评分表-----------------------------------------------------------20
摘 要
本设计主要要求分别以电话号码和用户名为关键字建立哈希表,并实现查找功能。所以本设计的核心问题是如何解决散列的问题,由于结点的个数无法确认,并且如果采用线性探测法散列算法,删除结点会引起“信息丢失”的问题。所以采用链地址法散列算法。采用链地址法,当出现同义词冲突时,使用链表结构把同义词链接在一起。
首先,解决的是定义链表结点,在链接地址法中,每个结点对应一个链表结点,它由三个域组成,而由于该程序需要分别用电话号码和用户名为关键字建立哈希表,所以该链表结点它是由四个域组成.name[8] 、num[11]和address[20]都是char浮点型采用链地址法,其中的所有同义词构成一个单链表,再由一个表头结点指向这个单链表的第一个结点。这些表头结点组成一个一维数组,即哈希表。
二,设计要求与分析
2.1 课程设计要求
设计哈希表实现电话号码查询系统。设计程序完成以下要求:
(1)设每个记录有下列数据项:电话号码、用户名、地址;
(2)从键盘输入各记录,分别以电话号码和用户名为关键字建立哈希表;
(3)采用再哈希法解决冲突;
(4)查找并显示给定电话号码的记录;
(5)查找并显示给定用户的记录。
2.2 程序分析
具体思路为:
(1)对于以号码为关键字的散列函数,是将十一个数字全部相加,然后对20求余。得到的数作为地址。对于以用户名为关键字的散列函数,是将所有字母的ASCLL码值相加,然后对20求余。
(2)要添加用户信息,即要有实现添加结点的功能的函数,所以要设计一个必须包括一个输入结点信息、添加结点的函数;
(3)要实现查找函数,则必须包括一个查找结点的函数;
另外还有一个必不可少的就是运行之后要有一个主菜单,即要设计一个主函数(main())。
(4)测试数据的选择最后,程序完成后要对程序进行编译调试,执行后要选择数据进行测试,这里选择的测试数据为:
1.姓名:郑健;电话:1234567;地址:江西九江;
2.姓名:吴任;电话:2345678;地址:江西南昌;
3.姓名:黄鑫;电话:3456789;地址:江西上饶;
三,数据结构选择与概要设计
3.1 数据结构选择
本设计涉及到的数据结构为:哈希表。要求输入电话号码、用户名、地址三个信息,并要求分别以电话号码和用户名为关键字进行查找,所以本问题要用到两个哈希函数,进行哈希查找。
在链地址法中,每个结点对应一个链表结点,它由三个域组成,而由于该程序需要分别用电话号码和用户名为关键字建立哈希表,所以该链表结点它是由四个域组成,链接地址法结点结构如图:
其中name[8]和num[11]是分别为以电话号码和用户名为关键字域,存放关键字(key);address[20](data)为结点的数据域,用来存储用户的地址。Next指针是用来指向下一个结点的地址。
3.2 Hash函数流程图
以号码为关键字的hash函数流程图
以姓名为关键字的hash函数流程图
添加信息节点流程图
姓名查找流程图
号码查询流程图
四,设计算法
4.1 建立节点
struct node
{
char name[8],address[20];
char num[11];
node * next;
};
typedef node* pnode; //可以为一个已有的数据类型声明多个别名,这里为该类型声明了两个指针
typedef node* mingzi;
node **phone;
node **nam;
node *a;
4.2 哈希函数的定义
本程序要设计两个hash()函数,分别对应电话号码和用户名。对关键字进行模运算,将运算结果所得的余数作为关键字(或结点)的存储地址,方法如下:以电话号码为关键字建立哈希函数hash(char num[11])。以用户名为关键字建立哈希函数hash2(char name[8])。利用强制类型转换,将用户名的每一个字母的ASCLL码值相加并且除以20后的余数。将计算出来的数作为该结点的地址赋给key2。
void hash(char num[11]); //以电话号码为关键字建立哈希函数
//哈希函数的主旨是将电话号码的十一位数字全部加起来
{
int i = 3;
key=(int)num[2];
while(num[i]!=NULL)
{
key+=(int)num[i];
i++;
}
key=key%20; } //利用强制类型转换,将用户名的每一个字母的ASCLL码值相加并且除以20后的余数
void hash2(char name[8]); //哈希函数 以用户名为关键字建立哈希函数
{
int i = 1;
key2=(int)name[0];
while(name[i]!=NULL)
{
key2+=(int)name[i];
i++;
}
key2=key2%20;
}
4.3 哈希查找
想要实现查找功能,同样需要两个查找函数,无论以用户名还是以电话号码为关键字,首先,都需要利用hash函数来计算出地址。再通过比对,如果是以电话号码为关键字,比较其电话号码是否相同,如果相同则输出该结点的所有信息,如果以用户名为关键字,则比较用户名是否相同,如果相同则输出该结点的所有信息。如果找不到与之对应相同的,则输出“无此记录”。
void find(char num[11]) ; //在以电话号码为关键字的哈希表中查找用户信息
{
hash(num);
node *q=phone[key]->next;
while(q!= NULL)
{
if(strcmp(num,q->num)==0)
break;
q=q->next;
}
if(q)
printf("%s_%s_%s\n",q->name,q->address,q->num);
else printf("无此记录\n");
}
void find2(char name[8]) ;// 在以用户名为关键字的哈希表中查找用户信息
{
hash2(name);
node *q=nam[key2]->next;
while(q!= NULL)
{
if(strcmp(name,q->name)==0)
break;
q=q->next;
}
4.4 程序测试
首先键入0,添加结点信息,然后按1进行查找,分别进行号码和姓名查找,最后可在主菜中,
选择号码散列和姓名散列,由此查看程序运行结果。
至此,就解决了哈希表的设计与实现算法可能出现的各种问题,那么根据以上思路以及对问题的分析和对出现情况的解决则可以写出源程序。
五,使用说明与测试结果
5.1 使用说明
由于address[20]、name[8]和num[11]可以看出地址可输入的最大字符数是20,姓名可输入的最大字符数是8,电话号码都为11位。
5.2 主菜单截图
5.3 添加记录截图
5.4 查找截图
5.5 散列结果截图
5.6 清空记录截图
六,程序源代码及实验心得
6.1 源代码
#include<stdio.h>
#include<string.h>
#define NULL 0
unsigned int key;
unsigned int key2;
int *p;
struct node
{
char name[8],address[20];
char num[11];
node * next;
};
typedef node* pnode;
typedef node* mingzi;
node **phone;
node **nam;
node *a;
void hash(char num[11])
{
int i = 3;
key=(int)num[2];
while(num[i]!=NULL)
{
key+=(int)num[i];
i++;
}
key=key%20;
}
void hash2(char name[8])
{
int i = 1;
key2=(int)name[0];
while(name[i]!=NULL)
{
key2+=(int)name[i];
i++;
}
key2=key2%20;
}
node* input()
{
node *temp;
temp = new node;
temp->next=NULL;
printf("请输入姓名:\n");
scanf("%s",temp->name);
printf("输入地址: \n");
scanf("%s",temp->address);
printf("输入电话:\n");
scanf("%s",temp->num);
return temp;
}
int apend()
{
node *newphone;
node *newname;
newphone=input();
newname=newphone;
newphone->next=NULL;
newname->next=NULL;
hash(newphone->num);
hash2(newname->name);
newphone->next = phone[key]->next;
phone[key]->next=newphone;
newname->next = nam[key2]->next;
nam[key2]->next=newname;
return 0;
}
void create()
{
int i;
phone=new pnode[20];
for(i=0;i<20;i++)
{
phone[i]=new node;
phone[i]->next=NULL;
}
}
void create2()
{
int i;
nam=new mingzi[20];
for(i=0;i<20;i++)
{
nam[i]=new node;
nam[i]->next=NULL;
}
}
void list()
{
int i;
node *p;
for(i=0;i<20;i++)
{
p=phone[i]->next;
while(p)
{
printf("%s_%s_%s\n",p->name,p->address,p->num);
p=p->next;
}
}
}
void list2()
{
int i;
node *p;
for(i=0;i<20;i++)
{
p=nam[i]->next;
while(p)
{
printf("%s_%s_%s\n",p->name,p->address,p->num);
p=p->next;
}
}
}
void find(char num[11])
{
hash(num);
node *q=phone[key]->next;
while(q!= NULL)
{
if(strcmp(num,q->num)==0)
break;
q=q->next;
}
if(q)
printf("%s_%s_%s\n",q->name,q->address,q->num);
else printf("无此记录\n");
}
void find2(char name[8])
{
hash2(name);
node *q=nam[key2]->next;
while(q!= NULL)
{
if(strcmp(name,q->name)==0)
break;
q=q->next;
}
if(q)
printf("%s_%s_%s\n",q->name,q->address,q->num);
else printf("无此记录\n");
}
void menu() //菜单
{
printf("0.添加记录\n");
printf("1.查找记录\n");
printf("2.姓名散列\n");
printf("3.号码散列\n");
printf("4.清空记录\n");
printf("5.退出系统\n");
}
int main()
{
char num[11];
char name[8];
create();
create2() ;
int sel;
while(1)
{
menu();
scanf("%d",&sel);
if(sel==1)
{
printf("6号码查询,7姓名查询\n");
int b;
scanf("%d",&b);
if(b==6)
{
printf("请输入电话号码:\n");
scanf("%s",num);
printf("输出查找的信息:\n");
find(num);
}
else
{
printf("请输入姓名:\n");
scanf("%s",name);
printf("输出查找的信息:\n");
find2(name);}}
if(sel==2)
{printf("姓名散列结果:\n");
list2();}
if(sel==0)
{printf("请输入要添加的内容:\n");
apend();}
if(sel==3)
{printf("号码散列结果:\n");
list();
}
if(sel==4)
printf("列表已清空:\n");
create();create2();}
if(sel==6) return 0;
}
return 0;
}
6.2 实验心得
一周的课程设计今天结束了。很快,收获很多。感觉像是一个从无到有的过程,非常的充实。我做的课题是“哈希表问题”。基本算法老师在课堂上有涉及过,但具体的还要靠自己去钻研。我在一边做上机实验时,一边到图书馆查阅书籍,反复实践操作,往往比书本上得到的更多,体会也更深刻。通过本次课程设计对哈希表问题有了一个比较全面的认识和了解。
哈希表问题,在存储位置和关键字之间建立对应关系f,根据对应关系f找到定值K。若结构中存在关键字和定值K相等的记录,必定在f(K)的存储位置上,由此可以省去比较过程,直接找到所查记录。哈希表其实不难,课程设计考验的是我们的学习态度,独立思考问题,和解决问题的能力。把握这次机会肯定大有收获。
东华理工学院长江学院
课程设计评分表
学生姓名: 郑 健 班级:083221 学号:08322126
课程设计题目:哈希表问题