实验七 查找
一、哈希表/散列表
简单的来说将数据按规律放,然后按照规律来查找的这么一个存放数据的表
它通过一个关键值的函数将所需的数据映射到表中对应的位置来存放数据和访问数据
这个映射的函数就叫做散列函数
这个存放记录的表就叫做散列表
二、构造哈希表的方法
1、.直接定址法
取关键字的某个线性函数为散列地址,Hash(Key)= Key 或 Hash(Key)= A*Key + B,A、B为常数。
优点:简单没有哈希冲突
缺点:所开辟的空间过大,利用率不高
2、除留余数法
取关键值被某个不大于散列表长m的数p除后的所得的余数为散列地址。Hash(Key)= Key % P。
优点:空间利用率高
缺点:设计复杂,要处理哈希冲突
三、哈希冲突/哈希碰撞
不同的Key值经过哈希函数Hash(Key)处理以后可能产生相同的值哈希地址,我们称这种情况为哈希冲突。任意的散列函数都不能避免产生冲突
四、影响哈希表效率的因素
(1)哈希函数是否均匀
(2)处理冲突的方法
(3)哈希表的负载因子(简单的来说就是填入表中的元素个数/散列表的长度)
处理哈希冲突的开链法(哈希桶)
闭散列最大的局限性就是空间利用率低,例如载荷因子为0.7,那么仍有0.3的空间未被利用
使用开链法可以使载荷因子为1,每个链上都挂常数个数据,对于哈希表的开链法来说,其开的空间都是按素数个依次往后开的空间
· 那么什么时候扩容呢?当每个链上都挂上数据之后,载荷因子为1的时候,就可以开始扩容了
具体过程如下图所示:
2.(必做题)实现哈希表的构造和查找算法,要求:用除留余数法构造哈希函数,分别用一次探测再散列、二次探测再散列解决冲突。
线性探测法
若产生冲突则放入下一个空闲区域 但是当数据多 需要发费很多的时间寻找空单元 更糟糕的是,即使表比较空,占据的单元会出现聚集现象,称之为一次聚集 为了解决一次聚集现象 出现了平方探测法
平方探测法
当出现冲突时 寻找空闲区域的步长以平方长度来计算,±i^2 就是 1 -1 4 -4 9 -9 16 -16 25 ……等长度去寻找下一个空白单元,这样的话冲突之间的距离分布相对均匀,解决了一次聚集的现象。但是平方探测法虽然解决了一次聚集的情况但是散列到同一位置的那些元素将探测相同的备选单元(就是冲突占用的单元再发生冲突其寻找空白单元的位置都是一样的,出现了循环) 这就叫做二次聚集
抄来的参考代码如下:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<malloc.h>
#include<math.h>
#include<conio.h>
#include<ctype.h>
#include<windows.h>
#include<time.h>
#define TURE 1
#define FLASE 0
#define ERROR 0
#define OK 1
#define SIZE 100
typedef int ElemType;
typedef struct {
ElemType key;
} keytype;
typedef struct {
keytype elem[SIZE];
int length;/*当前记录元素的长度*/
int size;/*哈希表的总长*/
int select;/*解决冲突方法*/
} hashtable;
int hash(hashtable h,int k) {
return k%(h.size);
}
int hashOnce(hashtable h,int i,int p) {
p+=i;
return p%(h.size);
}
int d[SIZE];
int hashTwice(hashtable h,int i,int p) {
p+=d[i];
return p%(h.size);
}
int initHash(hashtable <