实验五:查找与排序(一):哈希查找
实验内容
针对某个集体(比如你所在的班级)中的“人名”设计一个哈希表,使得平均查找长度不超过R,完成相应的建表和查表程序
哈希查找
在开始哈希查找代码的编写之前,首先来简单了解一下哈希查找的概念
非常简单的一句话:“哈希查找是通过计算数据元素的存储地址进行查找的一种方法。”
也就是说,我们可以自定义一种方法,称为哈希函数假设为F,以现有的数据元素作为key,那么在这种自定义方法中对key进行操作,即得到F(key),也就对应着一个存储地址,将这种key–>value的对应关系记录起来就生成哈希表,我们就可以根据key在哈希表中查找到相应元素的位置,完成哈希查找
但是也存在特殊情况,就是两个或多个数据元素的key对应在了同一个地址,这个时候就需要适当的冲突消解策略来处理
…
看了上述基本描述之后我们,回归正题
哈希查找的操作步骤:
⑵根据选择的冲突处理方法解决地址冲突
⑶在哈希表的基础上执行哈希查找
本次实验采用除留余数法
实验设计
宏定义
#define H_SIZE 15//哈希表的长度
#define N_SIZE 8//名单长度
#define ERROR 0
#define OK 1
#define R 15//小于哈希表长度的R
1.数据结构的设计
设计哈希函数使其根据自身特点(名称的ascii码值)来对应在哈希表中存储
采用除留余数法
规定R=15,即平均查找长度不超过15,那么哈希函数生成地址为:ascii % R
采用链式结构来避免冲突,即具有相同ascii码值的项必然得到相同的哈希表位,则按照其处理的先后顺序,依次连接到该表位对应的链表末尾
设计两个结构体
typedef struct NameTable{
const char *name; //姓名
int ascii; //对应的ascii码
int length; //查找长度
NameTable* next;
}Name;
typedef Name* NameArray;
typedef struct HashTable{
int num;//哈希表表位链接点个数
NameTable* head;
NameTable* end;
}Hash;
typedef Hash** Hashlist;
- NameTable用来存储人名相关信息,查找长度和一个后向指针
- HashTable即为哈希表,定义对应的链表结点个数,头尾指针
- 两者合用构造出哈希链
对应于数据整合哈希表建立和基本查找操作,本次实验共有如下函数编写:
描述 | 对应函数 |
---|---|
初始化名单表 | void InitNameList |
创建hash表,创建哈希函数 | void CreatHush |
查找函数 | void Search |
打印名单 | void Print_NameList |
打印哈希表 | void Print_Hash |
小菜单显示 | void show |
主函数 | int main |
2.核心算法描述
哈希表创建
在主函数中定义
NameArray NameList=NULL;//名单
Hashlist Table=NULL;//哈希表向量
根据名单创建哈希表
void CreatHush(Hashlist &htable,NameArray &NameList)
实现
在函数体中为哈希表Table预先初始化H_SIZE个Hashlist指针向量作为哈希表指针向量,0号单元未用
htable = (Hashlist)malloc((H_SIZE+1) * sizeof(Hash*));//指针向量分配内存//0号单元未用
然后初始化Table为每一个向量所指处分配内存
for (i = 1; i <= H_SIZE; i++) //初始化哈希表//0号单元未用(1-15)
{
htable[i] = (Hash*)malloc(sizeof(Hash)); htable[i]->num = 0;
htable[i]->head = NULL;
htable[i]->end = NULL;
}
之后将NameList内储存的名单信息利用for循环给哈希表赋值,NameList中人名已在InitNameList中初始化完成,也可以在其中自定义更改,或者通过外部文件读写方式读入
此处利用除留取余法定位哈希表对应位置,并考虑有无冲突两种情况
- 无冲突时哈希表链接点个数值num为初值0,此时直接将其链接至哈希表首链接点head之后
- 若遇到冲突即num!=0时,则以链式结构解决冲突,即在key位点处找到链表末尾记录,并将此时遭遇冲突记录连接至其末尾
- 根据记录所在哈希表中查找次数赋值length成员变量,即为前一记录基础上+1,完成哈希表的创建
哈希表查找
哈希查找是在哈希表创建基础上完成,这里假设是将所有班级人员名单均录入其中,生成完整的哈希表,不存在名称正确而找不到情况,当然也可以在判断查找失败之后自定义添加扩充哈希表
考虑一定可以查找到的情况,那么就是从键盘获取学生姓名