Hash(散列)建表及查找

散列方法

不用比较就能直接计算出记录的存储地址,从而找到所要的结点

Hash表

1)、定义

根据设定的散列函数和相应解决冲突的方法为一组结点建立的一张表,表中的结点的存储位置依赖于设定的散列函数和处理冲突的方法
如图:
在这里插入图片描述

2)、基本思想

设计1个hash函数,计算hash函数,其函数值恰好是key在Hash表中的地址
即,locate(key)= hash(key)

3)、冲突

若对于不同的键值k1和k2,且k1≠ k2,但hash(k1)= hash(k2)
即,k1和k2具有相同的散列地址,这种现象称为冲突
称k1、k2为同义词

4)、表长(m)的选取

设关键字个数为n,则:

n/m ≈ 3/4
5)、装载/负载因子
α = 表中填入的记录数 / Hash表的长度

Hash函数的构造方法

原则:使产生冲突的可能性降到尽可能的小

1)、直接定址法

哈希函数为关键字的线性函数
如:hash(key)= a * key + b

2)、数字分析法

若关键字集合中的每个关键字都是由s位数字组成,分析关键字集中的全体,并从中提取分布均匀的若干位或它们的组合作为地址

3)、平方取中法

若关键字的每一位都有些数字重复出现频度很高的现象,则先求关键字的平方值,以通过“平方值”过大差别,同时平方值的中间几位受到整个关键字中各位的影响
如:
在这里插入图片描述

4)、折叠法

若关键字的位数比较长,则可将其分割成几个部分,然后取它们的叠加和为哈希地址
两种处理方法,对关键字0442205864
①移位叠加
在这里插入图片描述
②间界叠加
在这里插入图片描述

5)、除留余数法

选择一个适当的正整数p,用p去除关键值,取其余数作为散列地址

hash(key)= key%p (p ≤ m)

p值的选取:小于m(表长)的最大质数

6)、随机数法
hash(key)= Random(key)

冲突的处理

1)、链地址法

将具有相同散列地址的记录都存储在同一个线性链表中
如图:使用hash(key)= key%17 (m=17、p=17)
y9ibG9nLmNzZG4ubmV0L3FxXzQxODkxODA1,size_16,color_FFFFFF,t_70)

2)、开放定址法

当冲突发生时,使用某种方法在散列表中形成一个探查序列,沿着此序列逐个地址去探查,直到找到一个开放的地址(未存放数据),将发生冲突的键值放到该地址中

①线性探测法

对给定的关键值k,若地址d(即hash key)发生冲突,则依次探查:
d+1、d+2、…、m-1、0、1、…、d-1

例,集合:{14,1,68,27,55,23,11,10,19,20,79,84}
若设表长为16,则使用hash(key)= key%13
在这里插入图片描述

②二次探测法

对给定的关键值k,若地址d(即hash key)发生冲突,则依次探查:
d+1、d-1、d+4、d-4、d+9、d-9、…

例,集合:{14,1,68,27,55,23,11,10,19,20,79,84}
若设表长为17,则使用hash(key)= key%17
在这里插入图片描述

③再散列探测法

对给定的关键值k,若地址d(即hash key)发生冲突,则依次探查:
(d+h(k))%m、(d+2h(k))%m、(d+3h(k))%m、…

h的选取方法,保证h(k)和m互质:
若m为素数:h(k) = k%(m-2) + 1
若m为2^i:h(k) = 1 ~ m-1 之间的任意奇数

3)、公共溢出区法

对具有相同散列地址的记录,将第1个放在hash表中,其余的都存储在同一个溢出区中

例,集合:{14,1,68,27,55,23,11,10,19,20,79,84}
若设表长为17,则使用hash(key)= key%17
在这里插入图片描述

Hash表的查找

查找过程和建表过程一致

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以帮你解答这个问题。 首先,我们需要确定哈希表的大小。由于班级人数为30,为了保证平均查找长度的上限为2,我们可以将哈希表的大小设置为15,也就是说,每个人在哈希表中对应的位置可以是0到14之间的整数。 接下来,我们可以选择使用除留余数法或线性探测再散列法来建立哈希表。以下是两种方法的实现: 1. 除留余数法 除留余数法是最简单的哈希函数之一,它的计算公式为: $h(k) = k \mod m$ 其中,$k$是关键字,$m$是哈希表的大小。我们可以将每个人的姓名转换成一个整数,然后使用除留余数法计算出它在哈希表中的位置。 下面是使用除留余数法建立哈希表的示例代码: ```python class HashTable: def __init__(self, size): self.size = size self.table = [None] * size def hash(self, key): return key % self.size def insert(self, key, value): index = self.hash(key) if self.table[index] is None: self.table[index] = (key, value) else: i = (index + 1) % self.size while i != index: if self.table[i] is None: self.table[i] = (key, value) break i = (i + 1) % self.size def search(self, key): index = self.hash(key) if self.table[index] is None: return None elif self.table[index][0] == key: return self.table[index][1] else: i = (index + 1) % self.size while i != index: if self.table[i] is None: return None elif self.table[i][0] == key: return self.table[i][1] i = (i + 1) % self.size return None ``` 在上面的代码中,我们使用了线性探测法来解决哈希冲突。如果某个位置已经被占用,我们就顺序往后查找,直到找到一个空位置为止。 2. 线性探测再散列法 线性探测再散列法是一种解决哈希冲突的方法,它的计算公式为: $h(k, i) = (h'(k) + i) \mod m$ 其中,$h'(k)$是第一次哈希函数的计算结果,$m$是哈希表的大小,$i$是一个变量,表示线性探测的步长。 下面是使用线性探测再散列法建立哈希表的示例代码: ```python class HashTable: def __init__(self, size): self.size = size self.table = [None] * size def hash(self, key): return key % self.size def rehash(self, key, i): return (self.hash(key) + i) % self.size def insert(self, key, value): i = 0 while i < self.size: index = self.rehash(key, i) if self.table[index] is None: self.table[index] = (key, value) break i += 1 def search(self, key): i = 0 while i < self.size: index = self.rehash(key, i) if self.table[index] is None: return None elif self.table[index][0] == key: return self.table[index][1] i += 1 return None ``` 在上面的代码中,我们使用了线性探测再散列法来解决哈希冲突。如果某个位置已经被占用,我们就按照线性探测的步长依次往后查找,直到找到一个空位置为止。 现在,我们可以将班级30个人的姓名插入到哈希表中,并进行查找。下面是示例代码: ```python names = ['Alice', 'Bob', 'Charlie', 'David', 'Emily', 'Frank', 'Grace', 'Henry', 'Isaac', 'Jack', 'Kate', 'Lily', 'Megan', 'Nancy', 'Oliver', 'Peter', 'Queen', 'Rose', 'Sam', 'Tom', 'Ursula', 'Victor', 'Wendy', 'Xavier', 'Yvonne', 'Zoe', 'Adam', 'Ben', 'Cathy'] # 使用除留余数法建立哈希表 hash_table1 = HashTable(15) for i, name in enumerate(names): hash_table1.insert(i, name) # 使用线性探测再散列法建立哈希表 hash_table2 = HashTable(15) for i, name in enumerate(names): hash_table2.insert(i, name) # 查找哈希表中的元素 print(hash_table1.search(3)) # David print(hash_table2.search(3)) # David ``` 在上面的代码中,我们先定义了30个人的姓名,然后分别使用除留余数法和线性探测再散列法建立了两个哈希表。最后,我们分别查找哈希表中关键字为3的元素,结果都是David。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值