- 该合辑为笔者自b站自学的“C++数据结构与算法”课程学习记录,旨在将重要的学习要点、思考内容与部分代码进行记录,以便后续自行翻看,亦可给其他读者带来一些参考
- 内容基于笔者自身的理解或感悟,可能存在不妥当或是错误之处
- 系统环境:Win10,Visual Studio 2019
- 文中图片参考东北大学“数据结构与算法设计” (2020) 线上课程讲义
目录
1. 哈希问题
2. 哈希函数
哈希问题
查找时间达到 O(1)
在查找算法中,最朴素的顺序查找法的时间性能为 O(n),即使是在数组有序的前提下进行二分查找,其性能也只能优化至 O(n),利用哈希相关技术,可以将此查找速度优化至常量阶 O(1) ,但要以牺牲一定内存空间作为代价
在哈希表中,常提供的函数有 Find,Insert 和Delete (较前两者没那么常用)等,而其余数据结构里面的查找最大最小值、找某个数据元素的前驱 / 后继节点、通过范围进行查找、遍历并以顺序输出等功能则在哈希表这个数据结构中难实现或无法实现
哈希函数
将数据映射到内存地址
哈希函数可以将数据映射到内存空间中,一个理想的哈希函数可以为每个数据都映射一个独一无二的内存空间,且只要数据完全相同,则无论何时运用哈希算法对其进行运算,得到的结果都是一样的,但在实际编程中,这样的理想哈希函数是不存在的,我们要做的就是尽量的使哈希函数的性能优化到我们可以接受的程度
在实际哈希函数的运作中,难免会产生冲突,也就是不同元素通过哈希算法进行运算后得到的结果相同,此时即称为“冲突”,为了解决此种冲突,我们可以从以下两方面进行探究:
- 尝试定义性能更好的哈希函数(结果不重复,且存入队列松散)
- 定义遇到冲突时的解决方法
除此之外,我们的哈希函数运算速度一定要尽可能的快,因为哈希表这样的数据结构的几乎所有操作都依赖于哈希算法的基速度
Separate Chaining 分离链接法
将计就计,用链表解决冲突
一种应对冲突时的解决方法,其主要思想是当不同元素通过哈希算法计算得出的结果相同时,以链表的形式将这两个(或后续的若干个)数据元素进行存储,如采用对10取余的哈希算法进行数据元素的存储时,会呈现以下结果:
Open Addressing 开放地址法
必须要给数据找到一个独自安身的家
另一种应对冲突的解决方法思路是不再在重复的内存空间上做文章,转而另辟蹊径,尝试通过某种方式查找另一块内存空间对数据进行存储,常见的方式有以下三种:
Linear probing (线性探测)
在结果重复时,通过将本应存入的存储空间进行线性的偏移,从而寻找空位对数据进行存储,偏移量f(i) = k,因其线性偏移的特点,故该种方法可能会造成“类聚”或者“扎堆”现象,即元素在我们分配好的存储空间内的一小部分紧密存储,这是我们所不希望看到的现象
Quadratic probing (二次方探测)
和线性探测不同的地方是,该方法的偏移量 f(i) = i ^ 2,因其偏移量的计算公式也不够随机,故也不可避免的会产生“类聚”现象
Double Hashing (再哈希法)
与上述两种方法不同的是,该种方法对于存储空间位置再选择的偏移量不再依托于一个随机性很差的算法,而是采用哈希算法,该种方法可以较好地规避数据元素的聚集,下图为各种方法所对应的平均搜索长度:
The End