当前位置:文档之家› 哈希表的设计与实现-数据结构与算法课程设计报告

哈希表的设计与实现-数据结构与算法课程设计报告

合肥学院计算机科学与技术系课程设计报告2009 ~2010 学年第二学期课程数据结构与算法课程设计名称哈希表的设计与实现学生姓名王东东学号0804012030专业班级08计本(2)指导教师王昆仑、李贯虹2010 年5 月课程设计目的“数据结构与算法课程设计”是计算机科学与技术专业学生的集中实践性环节之一,是学习“数据结构与算法”理论和实验课程后进行的一次全面的综合练习。

其目的是要达到理论与实际应用相结合,提高学生组织数据及编写程序的能力,使学生能够根据问题要求和数据对象的特性,学会数据组织的方法,把现实世界中的实际问题在计算机内部表示出来并用软件解决问题,培养良好的程序设计技能。

一、问题分析和任务定义1、问题分析要完成如下要求:设计哈希表实现电话号码查询系统。

实现本程序需要解决以下几个问题:(1)如何定义一个包括电话号码、用户名、地址的节点。

(2)如何以电话号码和用户名为关键字建立哈希表。

(3)用什么方法解决冲突。

(4)如何查找并显示给定电话号码的记录。

(5)如何查找并显示给定用户名的记录。

2 任务定义1、由问题分析知,本设计要求分别以电话号码和用户名为关键字建立哈希表,z在此基础上实现查找功能。

本实验是要我们分析怎么样很好的解决散列问题,从而建立一比较合理的哈希表。

由于长度无法确定,并且如果采用线性探测法散列算法,删除结点会引起“信息丢失”的问题。

所以采用链地址法散列算法。

采用链地址法,当出现同义词冲突时,可以使用链表结构把同义词链接在一起,即同义词的存储地址不是散列表中其他的空地址。

根据问题分析,我们可以定义有3个域的节点,这三个域分别为电话号码char num[30],姓名char name[30],地址char address[30]。

这种类型的每个节点对应链表中的每个节点,其中电话号码和姓名可分别作关键字实现哈希表的创建。

二、数据结构的选择和概要设计1、数据结构的选择数据结构:散列结构。

散列结构是使用散列函数建立数据结点关键词与存储地址之间的对应关系,并提供多种当数据结点存储地址发生“冲突”时的处理方法而建立的一种数据结构。

散列结构基本思想,是以所需存储的结点中的关键词作为自变量,通过某种确定的函数H(称作散列函数或者哈希函数)进行计算,把求出的函数值作为该结点的存储地址,并将该结点或结点地址的关键字存储在这个地址中。

散列结构法(简称散列法)通过在结点的存储地址和关键字之间建立某种确定的函数关系H,使得每个结点(或关键字)都有一个唯一的存储地址相对应。

当需要查找某一指定关键词的结点时,可以很方便地根据待查关键字K计算出对应的“映像”H(K),即结点的存储地址。

从而一次存取便能得到待查结点,不再需要进行若干次的比较运算,而可以通过关键词直接计算出该结点的所在位置。

2、概要设计(1)、哈希表的定义结点的数据类型:struct node //定义姓名地址电话号码{char name[30];char address[30];char num[30];node * next;}; ElemNode;(2)、哈希地址的计算以姓名为关键字的哈希地址计算:从取得的姓名第二个字母开始,取ASCII码累加,对30求余得所求哈希地址以电话号码为关键字的哈希地址计算:从号码第二位开始,将所有号码累加之后对30求模得哈希地址(3)、拉链法链地址法:在散表结构存放在指针指向的单元中。

链地址法在解决冲突时,使用链表结构把同义词链接在一起,即同义词的存储地址不是散列表中其他的空地址。

采用C语言定义如下:#define Max_length 100Typedef struct{int key;ElemType data;ElemNode *next;}ElemNode;Typedef struct{ElemNode *first;}ElemHeader,HashTable[Max_length];所有的同义词构成一个单链表,再由一个表头节点指向这个单链表的第一个节点。

这些镖头节点组成一个一维数组,即散列表。

数组元素的下标对应由散列函数求出的散列地址。

拉链法处理冲突的散列表结构158(4)链地址法查找结点的算法思想a、根据查找节点的关键字算出哈希地址b、在散列地址所指向的单链表中依次寻找节点c、如果找到,输出节点的信息;否则提示没有找到三、详细设计和编码主流程图。

以号码为关键字的Hash()函数流程图以姓名为关键字的Hash()函数流程图添加结点信息流程图:编码1、建立节点struct node //定义姓名地址电话号码{char name[30];char address[30];char num[30];node * next;};typedef node* pnode; //声明了已有数据类型的两个指针变量typedef node* mingzi;node **phone;node **nam;2、定义哈希函数这里我们需要定义两个哈希函数,一个以电话号码为关键字,另一个以姓名ASCII之和求模之后的值为关键字。

主要方法为将电话号码从第二位开始逐一累加并将所得结果对30求模得哈希地址;第二种则是将姓名字符进行强制类型转换之后得ASCII码相加对30求模得哈希地址。

=============================求哈希地址源代码========================== void hash(char num[30]) //哈希函数//将运算的结果所得的余数作为节点的存储地址{int i = 1;key=(int)num[0];while(num[i]!=NULL){key+=(int)num[i];i++;}key=key%30;}void hash2(char name[30]) //哈希函数//将运算的结果所得的余数作为节点的存储地址{int i = 1;key2=(int)name[0];while(name[i]!=NULL){key2+=(int)name[i];i++;}key2=key2%30;}=====================================================================(3)、添加节点接下来就是每个节点的建立,添加结点,利用链地址法解决冲突。

建立结点应包括动态申请内存空间。

向结点中输入信息。

同时将结点中的next指针等于NULL。

添加结点,首先需要利用哈希函数计算出地址即关键字,然后将所得数据插入到链表中。

===========================动态申请内存空间============================ void create_phone() //新建节点{int i;phone=new pnode[30];for(i=0;i<30;i++){phone[i]=new node;phone[i]->next=NULL;}}void create2_num() //新建节点{int i;nam=new mingzi[30];for(i=0;i<30;i++){nam[i]=new node;nam[i]->next=NULL;}}====================================================================================================添加节点=============================== int apend() //添加节点{node *newphone;node *newname;newphone=input();newname=newphone;newphone->next=NULL;newname->next=NULL;hash(newphone->num); //先计算号码的keyhash2(newname->name); //姓名的key2newphone->next = phone[key]->next;//把该key的号码链接到原来的号码的后一节点上phone[key]->next=newphone;newname->next = nam[key2]->next; //把该key的姓名链接到原来的号码的后一节点上nam[key2]->next=newname;return 0;}=====================================================================(4)、查找节点===================================================================== void find_num(char num[30]) //按号码查找用户信息{hash(num);node *q=phone[key]->next;while(q!= NULL){if(strcmp(num,q->num)==0)break;q=q->next;}if(q)cout<<q->name<<"_" <<q->address<<"_"<<q->num<<endl;else cout<<"无此记录"<<endl;}void find2_nam(char name[30]) //按姓名查找用户信息{hash2(name);node *q=nam[key2]->next;while(q!= NULL){if(strcmp(name,q->name)==0)break;q=q->next;}if(q)cout<<q->name<<"_" <<q->address<<"_"<<q->num<<endl;else cout<<"无此记录"<<endl;}=====================================================================(5)输出哈希表===================================================================== void list_num() //以号码为关键字显示列表{int i;node *p;for(i=0;i<30;i++){p=phone[i]->next;while(p){cout<<p->name<<'_'<<p->address<<'_'<<p->num<<endl;p=p->next;}}}void list2_nam() //以姓名为关键字显示列表{int i;node *p;for(i=0;i<30;i++){p=nam[i]->next;while(p){cout<<p->name<<'_'<<p->address<<'_'<<p->num<<endl;p=p->next;}}}=====================================================================(6)主函数main()四、上机调试1、在调试的时候,出现了无法查找姓名或者电话号码相同的用户的信息当查找姓名相同或者号码相同的用户时,就会出现死循环原先代码如下===================================部分代码=================================== while(q!= NULL){if(strcmp(num,q->num)==0)break;q=q->next;}if(q)cout<<q->name<<"_" <<q->address<<"_"<<q->num<<endl;else cout<<"无此记录"<<endl;}这个子函数只能查找一个符合条件的节点,查找到一个之后就跳出循环了,后经指导老师指出,改为===================================部分代码=================================== int flag;hash(num);node *q=phone[key]->next;while(q!= NULL){if(strcmp(num,q->num)==0){cout<<q->name<<"_" <<q->address<<"_"<<q->num<<endl;flag=1;}q=q->next;}if(flag==0) cout<<"无此记录"<<endl;}=============================================================================== 先前出现问题是因为break语句结束语句指能查找一个节点,改进之后可以实现功能2、文件的操作在这个程序中没有能成功实现,故在最后阶段,删除了这一功能。

相关主题