一般的线性表、树中,记录在结构中的相对位置是随机的,即和记录的关键字之间不存在确定的关系,因此,在结构中查找记录时需进行一系列和关键字的比较。这一类查找方法建立在“比较“的基础上,查找的效率依赖于查找过程中所进行的比较次数。 理想的情况是能直接找到需要的记录,因此必须在记录的存储位置和它的关键字之间建立一个确定的对应关系f,使每个关键字和结构中一个唯一的存储位置相对应。
哈希表中元素是由哈希函数确定的。将数据元素的关键字K作为自变量,通过一定的函数关系(称为哈希函数),计算出的值,即为该元素的存储地址。表示为: Addr = H(key)。为此在建立一个哈希表之前需要解决两个主要问题:
一、构造一个合适的哈希函数
常见的哈希函数:
(1)除留余数法 H(key)=key mod B
最简单的哈希函数是将数据除以某一个常数后,取余数来当索引。例如在一个有13个位置的数组中,只使用到7个地址,值分别是12、65、70、99、33、67、48。我们可以把数组内的值除以13,并以其余数来当数组的下标(即作为索引)。
(2)平方取中法
平方取中法和除留余数法相似,就是先计算数据的平方,之后再取中间的某段数字作为索引。在下例中,我们使用平方取中法,并将数据存放在100个地址空间中,其操作步骤如下:
将12、65、70、99、33、67、51平方后得144、4225、4900、9801、1089、4489、2601,再取百位数和十位数作为键值,分别为14、25、90、80、08、48、60
(3)折叠法
折叠法是将数据转换成一串数字后,先将这串数字拆成几个部分,再把它们加起来,就可以计算出这个键值的Bucket Address(桶地址)
二、冲突的处理
冲突:在哈希表中,不同的关键字值对应到同一个存储位置的现象。即关键字K1≠K2,但H(K1)= H(K2)。均匀的哈希函数可以减少冲突,但不能避免冲突。发生冲突后,必须解决;也即必须寻找下一个可用地址。
解决冲突的方法:
⑴链接法(拉链法)。将具有同一散列地址的记录存储在一条线性链表中。例,除留余数法中,设关键字为 (18,14,01,68,27,55,79),除数为13。散列地址为 (5,1,1,3,1,3,1)。
⑵开放定址法。如果h(k)已经被占用,按如下序列探查:(h(k)+p⑴)%TSize,(h(k)+p⑵)%TSize,…(h(k)+p(i))%TSize,
其中,h(k)为哈希函数,TSize为哈希表长,p(i)为探查函数。在 h(k)+p(i-1))%TSize的基础上,若发现冲突,则使用增量 p(i) 进行新的探测,直至无冲突出现为止。其中,根据探查函数p(i)的不同,开放定址法又分为线性探查法(p(i) = i : 1,2,3,…),二次探查法(p(i)=(-1)^(i-1)*((i+1)/2)^2,探查序列依次为:1, -1,4, -4, 9 …),随机探查法(p(i): 随机数),双散列函数法(双散列函数h(key) ,hp (key)若h(key)出现冲突,则再使用hp (key)求取散列地址。探查序列为:h(k),h(k)+ hp(k),…,h(k)+ i*hp(k))。
⑶桶定址法。桶:一片足够大的存储空间。桶定址:为表中的每个地址关联一个桶。如果桶已经满了,可以使用开放定址法来处理。例如,插入A5,A2,A3,B5,A9,B2,B9,C2,采用线性探查法解决冲突。如图:
三、设计一个python程序,使用链表来进行再哈希处理
import random
INDEXBOX=7 #哈希表元素个数
MAXNUM=13 #数据个数
class Node:
def __init__(self,val):
self.val=val
self.next=None
global indextable
indextable=[None]*INDEXBOX #声明动态数组
def create_table(val): #创建哈希表
global indextable
newnode=Node(val)
myhash=val%7 #哈希函数除以7取余数
current=indextable[myhash]
if current.next==None:
indextable[myhash].next=newnode
else:
while current.next!=None:
current=current.next
current.next=newnode
def print_data(val): #打印哈希表
global indextable
pos=0
head=indextable[val].next
print(' %2d:\t'%val,end='') #索引地址
while head!=None:
print('[%2d]-'%head.val,end='')
pos+=1
if pos%8==7:
print('\t')
head=head.next
print()
#主程序
data=[0]*MAXNUM
index=[0]*INDEXBOX
for i in range(INDEXBOX): #清除哈希表
indextable[i]=Node(-1)
print('原始数据:')
for i in range(MAXNUM):
data[i]=random.randint(1,30) #随机数建立原始数据
print('[%2d] '%data[i],end='')
if i%8==7:
print('\n')
print('\n哈希表:')
for i in range(MAXNUM):
create_table(data[i])
for i in range(INDEXBOX):
print_data(i)
print()
本文介绍了哈希表的工作原理,包括如何构造合适的哈希函数,如除留余数法、平方取中法和折叠法,并讨论了处理哈希冲突的策略,如链接法和开放定址法。最后,通过一个Python程序展示了如何使用链表进行再哈希处理。

1万+

被折叠的 条评论
为什么被折叠?



