Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

哈希表及其设计原理 #39

Open
kevinyan815 opened this issue Dec 30, 2020 · 0 comments
Open

哈希表及其设计原理 #39

kevinyan815 opened this issue Dec 30, 2020 · 0 comments

Comments

@kevinyan815
Copy link
Owner

哈希表、Map或者叫映射

哈希表是除了数组之外,最常见的数据结构。几乎所有的语言都会有数组和哈希表两种集合元素,哈希表也被称作字典或者映射。数组用于表示元素的序列,而哈希表示的是键值对之间映射关系。

设计原理

哈希表是计算机科学中的最重要数据结构之一,这不仅因为它 𝑂(1) 的读写性能非常优秀,还因为它提供了键值之间的映射。想要实现一个性能优异的哈希表,需要注意两个关键点 —— 哈希函数和冲突解决方法。

哈希函数

实现哈希表的关键点在于哈希函数的选择,哈希函数的选择在很大程度上能够决定哈希表的读写性能。在理想情况下,哈希函数应该能够将不同键映射到不同的索引上,这要求哈希函数的输出范围大于输入范围,但是由于键的数量会远远大于映射的范围,所以在实际使用时,这个理想的效果是不可能实现的。

比较实际的方式是让哈希函数的结果能够尽可能的均匀分布,然后通过工程上的手段解决哈希碰撞的问题。哈希函数映射的结果一定要尽可能均匀,结果不均匀的哈希函数会带来更多的哈希冲突以及更差的读写性能。

冲突解决

哈希函数输入的范围一定会远远大于输出的范围,所以在使用哈希表时一定会遇到冲突,哪怕我们使用了完美的哈希函数,当输入的键足够多也会产生冲突。所以仍然存在发生哈希碰撞的可能,这时就需要一些方法来解决哈希碰撞的问题,常见方法的就是开放寻址法和拉链法。

需要注意的是,这里提到的哈希碰撞不是多个键对应的哈希完全相等,可能是多个哈希的部分相等,例如:两个键对应哈希的前四个字节相同。

拉链法

与开放地址法相比,拉链法是哈希表最常见的实现方法,大多数的编程语言都用拉链法实现哈希表,它的实现比较开放地址法稍微复杂一些,但是平均查找的长度也比较短,各个用于存储节点的内存都是动态申请的,可以节省比较多的存储空间。

拉链法会使用链表数组作为哈希底层的数据结构,我们可以将它看成可以扩展的二维数组。

拉链法写入数据

当我们需要将一个键值对 (Key6, Value6) 写入哈希表时,键值对中的键 Key6 都会先经过一个哈希函数,哈希函数返回的哈希会帮助我们选择一个桶,和开放地址法一样,选择桶的方式是直接对哈希返回的结果取模:

index := hash("Key6") % array.len

选择了 桶后就可以遍历当前桶中的链表了,在遍历链表的过程中会遇到以下两种情况:

找到键相同的键值对 — 更新键对应的值;
没有找到键相同的键值对 — 在链表的末尾追加新的键值对;

拉链法读取数据

如果要在哈希表中获取某个键对应的值,也是一样,哈希函数返回的哈希会帮助我们选择一个桶,当哈希表发现它命中 4 号桶时,它会依次遍历桶中的链表,然而遍历到链表的末尾也没有找到期望的键,所以哈希表中没有该键对应的值。

在一个性能比较好的哈希表中,每一个桶中都应该有 01 个元素,有时会有 23 个,很少会超过这个数量。计算哈希、定位桶和遍历链表三个过程是哈希表读写操作的主要开销。

所有内容摘录自文章Golang哈希表的原理

@kevinyan815 kevinyan815 changed the title 哈希表,已经它的设计原理 哈希表及其设计原理 Dec 30, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant