7.4散列表的查找
7.4.1散列表的基本概念
基本思想:记录的存储位置域关键字之间存在对应关系
对应关系------hash函数
Loc(i)= H(keyi)
如何查找:
根据散列函数 H(key) = k
查找key=9,则访问H(4)= 18号地址,若内容为18则成功;
若查不到,则返回一个特殊值,如空指针或空记录。
优点:查找效率高
缺点:空间效率低
7.4.2散列表的若干术语
散列方法(杂凑法):
选取某个函数,依该函数按关键字计算元素的存储位置,并按此存放;
查找时,由同一个函数对给定值K计算地址,将k与地址单元中元素关键码进行比,确定查找是否成功。
散列函数(杂凑函数):散列方法中使用的转换函数
散列表(杂凑表):按上述思想构造的表 散列函数:H(key)=k
冲突:不同的关键码映射到同一个散列地址 key1≠key2,但是H(key1)=H(key2)
例如:有6个元素的关键码分别为:(25,21,39,9,23,11)。
- 选取关键码与元素位置间的函数为H(k)=k mod 7,
- 地址编号从0-6
7.4.3散列函数的构造方法
散列存储:选取某个函数,依该函数按关键字计算元素的存储位置
Loc(i)=H(keyi)
在散列查找方法中,冲突是不可能避免的,只能尽可能减少。
使用散列表要解决好两个问题:
-
构造好的散列函数
a)所选函数尽可能简单,以便提高转换速度;
b)所选函数对关键码计算出的地址,应在散列地址集中致均匀分布,以减少空间浪费。
-
制定一个好的解决冲突的方案
查找时,如果从散列函数计算出的地址中查不到关键码,则应当依据解决冲突的规则,有规律地查询其他相关单元。
构造散列函数考虑的因素:
- 执行速度(即计算散列函数所需要的时间);
- 关键字的长度;
- 散列表的长度;
- 关键字的分布情况;
- 查找频率。
根据元素集合的特性构造
- 要求一 :n 个数据源仅占用 n 个地址,虽然散列查找是以空间换时间,但仍希望散列的地址空间尽量小。
- 要求二 :无论用什么方法存储,目的都是尽量均匀地存放元素,以避免冲突。
1、直接定址法
Hash(key)= a·key + b (a、b为常数)
优点:以关键码key的某个线性函数值为散列地址,不会产生冲突。
缺点:要占用连续地址空间,空间效率低。
2、除留余数法
Hash(key)= key mod p(p是一个整数)
关键:如何选取合适的p?
技巧:设表长为m,取p≤m且为质数
7.4.4处理冲突的方法
1、开放地址法(开地址法)
基本思想:有冲突时就去寻找下一个空的散列地址,只要散列表足够大,空的散列地址总能找到,并将数据元素存入。
例如:除留余数法 H~i~=(Hash(key)+d~i~) mod m d~i~为增量序列
常用方法:
线性探测法 d~i~为1,2,...m-1线性序列 一旦冲突,就找下一个地址,直到找到空地址存入
二次探测法 d~i~为1^2^,-1^2^,2^2^,-2^2^,...,q^2^二次序列
伪随机探测法 d~i~为伪随机数序列
2、链地址法(拉链法)
基本思想:相同散列地址的记录链成一单链表
m个散列地址就设m个单链表,然后用一个数组将m个单链表的表头指针存储起来,形成一个动态的结构。
链地址法建立散列表步骤:
- Step1:取数据元素的关键字key,计算其散列函数值(地址)。若该地址对应的链表为空,则将该元素插入此链表;否则执行Step2解决冲突。
- Step2:根据选择的冲突处理方法,计算关键字key的下一个存储地址。若该地址对应的链表不为空,则利用链表的前插法或后插法将该元素插入此链表。
链地址法的优点:
- 非同义词不会冲突,无聚集现象
- 链表上结点空间动态申请,更适合于表长不确定的情况
7.4.5散列表的查找
给定值查找值k,查找过程: