分离链接法 / Separate Chain Hashing


前面完成了一个基本散列表的实现,但是还存在一个问题,当散列表插入元素冲突时,散列表将返回异常,这一问题的解决方式之一为使用链表进行元素的存储,即分离链接法。

Separate Chain Hashing:
[0] Header->11->0->110
[1] Header->12->1->111
[2] Header->2->112
[3] Header->14->3->113
[4] Header->15->4->114
[5] Header->16->5
[6] Header->17->6
[7] Header->18->7
[8] Header->19->8
[9] Header->9
[10] Header->10

而在利用链表实现分离链接法时,可选用带表头的链表,插入元素时采用前端插入,每次将新元素插入对应散列位置链表的最前端,因为新插入的元素往往被查找的概率较大,放在前面便于缩短查找时间。

下面利用代码实现散列表的分离链接法,

完整代码

 from hash_table import HashTable, kmt_hashing
from linked_list.linked_list_dummy_header import LinkedListDummyHeader as List class SeparateChainHashing(HashTable):
"""
Separate Chain Hashing:
[0] Header->11->0->110
[1] Header->12->1->111
[2] Header->2->112
[3] Header->14->3->113
[4] Header->15->4->114
[5] Header->16->5
[6] Header->17->6
[7] Header->18->7
[8] Header->19->8
[9] Header->9
[10] Header->10
"""
def __init__(self, size, fn):
self._array = [List() for i in range(size)]
self._hashing = fn def find(self, item):
linked_list = self._array[self._hashing(item)]
node = linked_list.header.next
while node and node.value != item:
node = node.next
return node def _insert(self, item):
"""
item
|
V
[n] Header->node_1->node_2->node_3
"""
if item is None:
return
linked_list = self._array[self._hashing(item)]
node = linked_list.header
while node.next:
if node.next.value == item: # Element existed
return
node = node.next
linked_list.insert(item, 1) def delete(self, item):
linked_list = self._array[self._hashing(item)]
linked_list.delete(item) def show(self):
print(self) @property
def load_factor(self):
element_num = sum(x.length-1 for x in self._array)
return element_num/self.size def make_empty(self):
# self._array = [List() for i in range(len(self._array))]
for chain in self._array:
chain.clear() def test(h):
print('\nShow hash table:')
h.insert(110, 111, 112, 113, 114)
h.insert(range(20))
h.delete(13)
h.show()
print('\nLoad factor is:', h.load_factor)
print('\nClear hash table:')
h.make_empty()
h.show() if __name__ == '__main__':
test(SeparateChainHashing(11, kmt_hashing(11)))

分段解释

首先导入散列表和散列函数,以及需要用到的带表头链表,

 from hash_table import HashTable, kmt_hashing
from linked_list.linked_list_dummy_header import LinkedListDummyHeader as List

接着基于散列表派生一个实现分离链接法的散列表类,

 class SeparateChainHashing(HashTable):
"""
Separate Chain Hashing:
[0] Header->11->0->110
[1] Header->12->1->111
[2] Header->2->112
[3] Header->14->3->113
[4] Header->15->4->114
[5] Header->16->5
[6] Header->17->6
[7] Header->18->7
[8] Header->19->8
[9] Header->9
[10] Header->10
"""
def __init__(self, size, fn):
self._array = [List() for i in range(size)]
self._hashing = fn

重载find方法,在查找到散列值对应的链表后,遍历链表查询目标值,

     def find(self, item):
linked_list = self._array[self._hashing(item)]
node = linked_list.header.next
while node and node.value != item:
node = node.next
return node

重载_insert方法,插入元素时,向链表表头后的第一个位置进行插入,

     def _insert(self, item):
"""
item
|
V
[n] Header->node_1->node_2->node_3
"""
if item is None:
return
linked_list = self._array[self._hashing(item)]
node = linked_list.header
while node.next:
if node.next.value == item: # Element existed
return
node = node.next
linked_list.insert(item, 1)

重载delete方法,删除元素较为简单,查找到散列值对应的链表后,使用链表的删除函数即可,

     def delete(self, item):
linked_list = self._array[self._hashing(item)]
linked_list.delete(item)

最后,分别完成显示散列表,计算装填因子和清空散列表的函数,

     def show(self):
print(self) @property
def load_factor(self):
element_num = sum(x.length-1 for x in self._array)
return element_num/self.size def make_empty(self):
# self._array = [List() for i in range(len(self._array))]
for chain in self._array:
chain.clear()

完成散列表类后,再写一个测试函数,用于测试散列表,以 11 为散列表大小初始化一个散列表进行测试

 def test(h):
print('\nShow hash table:')
h.insert(110, 111, 112, 113, 114)
h.insert(range(20))
h.delete(13)
h.show()
print('\nLoad factor is:', h.load_factor)
print('\nClear hash table:')
h.make_empty()
h.show() if __name__ == '__main__':
test(SeparateChainHashing(11, kmt_hashing(11)))

最后得到结果

Show hash table:
[0] Header->11->0->110
[1] Header->12->1->111
[2] Header->2->112
[3] Header->14->3->113
[4] Header->15->4->114
[5] Header->16->5
[6] Header->17->6
[7] Header->18->7
[8] Header->19->8
[9] Header->9
[10] Header->10 Load factor is: 2.1818181818181817 Clear hash table:
[0] Header
[1] Header
[2] Header
[3] Header
[4] Header
[5] Header
[6] Header
[7] Header
[8] Header
[9] Header
[10] Header

可以看到,由于链表的存在,冲突被很好的解决了。而另一种冲突解决方式,可参考相关阅读中的开放定址法

相关阅读


1. 散列表

2. 开放定址法

Python与数据结构[4] -> 散列表[1] -> 分离链接法的 Python 实现的更多相关文章

  1. Python与数据结构[4] -> 散列表[2] -> 开放定址法与再散列的 Python 实现

     开放定址散列法和再散列 目录 开放定址法 再散列 代码实现 1 开放定址散列法 前面利用分离链接法解决了散列表插入冲突的问题,而除了分离链接法外,还可以使用开放定址法来解决散列表的冲突问题. 开放定 ...

  2. Python与数据结构[4] -> 散列表[0] -> 散列表与散列函数的 Python 实现

    散列表 / Hash Table 散列表与散列函数 散列表是一种将关键字映射到特定数组位置的一种数据结构,而将关键字映射到0至TableSize-1过程的函数,即为散列函数. Hash Table: ...

  3. Nginx数据结构之散列表

    1. 散列表(即哈希表概念) 散列表是根据元素的关键码值而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录, 以加快查找速度.这个映射函数 f 叫做散列方法,存放记录的数 ...

  4. JAVA数据结构--哈希表的实现(分离链接法)

    哈希表(散列)的定义 散列表(Hash table,也叫哈希表),是根据关键码值(Key value)而直接进行访问的数据结构.也就是说,它通过把关键码值映射到表中一个位置来访问记录,以加快查找的速度 ...

  5. 解决hash冲突之分离链接法

    解决hash冲突之分离链接法 分离链接法:其做法就是将散列到同一个值的所有元素保存到一个表中. 这样讲可能比较抽象,下面看一个图就会很清楚,图如下 相应的实现可以用分离链接散列表来实现(其实就是一个l ...

  6. 分离链接法(Separate Chaining)

    之前我们说过,对于需要动态维护的散列表 冲突是不可避免的,无论你的散列函数设计的有多么精妙.因此我们解决的重要问题就是:一旦发生冲突,我们该如何加以排解? 我们在这里讨论最常见的两种方法:分离链接法和 ...

  7. POJ2549【hash分离链接法】

    题意: 给n个不同的数,求一个4个数(a,b,c,d)的组合满足a+b+c=d;求最大的d. 思路: 没想到可以用hash搞/ 这个就是数据结构里的分离链接法~ 解决hash冲突的方法:将所有关键字为 ...

  8. jdk1.8HashMap底层数据结构:散列表+链表+红黑树,jdk1.8HashMap数据结构图解+源码说明

    一.前言 本文由jdk1.8源码整理而得,附自制jdk1.8底层数据结构图,并截取部分源码加以说明结构关系. 二.jdk1.8 HashMap底层数据结构图 三.源码 1.散列表(Hash table ...

  9. JS中数据结构之散列表

    散列是一种常用的数据存储技术,散列后的数据可以快速地插入或取用.散列使用的数据 结构叫做散列表.在散列表上插入.删除和取用数据都非常快. 下面的散列表是基于数组进行设计的,数组的长度是预先设定的,如有 ...

随机推荐

  1. [学习笔记]Tarjan&&欧拉回路

    本篇并不适合初学者阅读. SCC: 1.Tarjan缩点:x回溯前,dfn[x]==low[x]则缩点. 注意: ①sta,in[]标记. ②缩点之后连边可能有重边. 2.应用: SCC应用范围还是很 ...

  2. C# Async await和Task的关系

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

  3. [SCOI2007] 蜥蜴 (最大流)

    [SCOI2007] 蜥蜴 题目背景 07四川省选 题目描述 在一个r行c列的网格地图中有一些高度不同的石柱,一些石柱上站着一些蜥蜴,你的任务是让尽量多的蜥蜴逃到边界外. 每行每列中相邻石柱的距离为1 ...

  4. Kafka自我学习3-Scalable

    1.After created the zookeeper cluster, we found all broker cluster topic can be find in zoo1, zoo2, ...

  5. 如何把SSL公钥和私钥转化为PFX格式

    1.登陆   https://myssl.com/cert_convert.html 2.原格式选择为 “PEM”,目标格式选择为 “PKCS12” 3.上传cer到 ”证书文件“,上传key到 ”私 ...

  6. 关于JAVA正则匹配空白字符的问题(全角空格与半角空格)

    今天遇到一个字符串,怎么匹配空格都不成功!!! 我把空格复制到test.properties文件 显示“\u3000” ,这是什么? 这是全角空格!!! 查了一下    \s    不支持全角 1.& ...

  7. MyBatis系列四 之 智能标签进行查询语句的拼接

    MyBatis系列四 之 智能标签进行查询语句的拼接 使用Foreach进行多条件查询 1.1 foreach使用数组进行多条件查询 在MyBatis的映射文件中进行如下配置 <!--根据数组进 ...

  8. 【洛谷 P4777】 【模板】扩展中国剩余定理(EXCRT)

    注意一下:: 题目是 \[x≡b_i\pmod {a_i}\] 我总是习惯性的把a和b交换位置,调了好久没调出来,\(qwq\). 本题解是按照 \[x≡a_i\pmod {b_i}\] 讲述的,请注 ...

  9. bzoj 1026 DP,数位统计

    2013-11-20 08:11 原题传送门http://www.lydsy.com/JudgeOnline/problem.php?id=1026 首先我们用w[i,j]表示最高位是第i位,且是j的 ...

  10. hdu 4506 小明系列故事——师兄帮帮忙

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4506 题目大意:找规律,判断k的t次幂前面的系数. #include <iostream> ...