关于书店网站开发实例的书,做三角渐变用哪个网站,响应式网站怎么做pc端的,郑州seo关键词排名优化前面我们已经讲到了数组和链表#xff0c;数组能通过下标 O(1) 访问#xff0c;但是删除一个中间元素却要移动其他元素#xff0c;时间 O(n)。 循环双端链表倒是可以在知道一个节点的情况下迅速删除它#xff0c;但是吧查找又成了 O(n)。难道就没有一种方法可以快速定位和删…前面我们已经讲到了数组和链表数组能通过下标 O(1) 访问但是删除一个中间元素却要移动其他元素时间 O(n)。 循环双端链表倒是可以在知道一个节点的情况下迅速删除它但是吧查找又成了 O(n)。难道就没有一种方法可以快速定位和删除元素吗似乎想要快速找到一个元素除了知道下标之外别无他法于是乎聪明的计算机科学家又想到了一种方法。 能不能给每个元素一种『逻辑下标』然后直接找到它呢哈希表就是这种实现。它通过一个哈希函数来计算一个元素应该放在数组哪个位置当然对于一个 特定的元素哈希函数每次计算的下标必须要一样才可以而且范围不能超过给定的数组长度。我们还是以书中的例子说明假如我们有一个数组 T包含 M13 个元素我们可以定义一个简单的哈希函数 hh(key) key % M这里取模运算使得 h(key) 的结果不会超过数组的长度下标。我们来分别插入以下元素765, 431, 96, 142, 579, 226, 903, 388先来计算下它们应用哈希函数后的结果:下边我画个图演示整个插入过程(纯手工绘制原谅我字写得不太优雅):哈希冲突 (collision)这里到插入 226 这个元素的时候不幸地发现 h(226) h(96) 5不同的 key 通过我们的哈希函数计算后得到的下标一样 这种情况成为哈希冲突。怎么办呢聪明的计算机科学家又想到了办法其实一种直观的想法是如果冲突了我能不能让数组中 对应的槽变成一个链式结构呢这就是其中一种解决方法叫做 链接法(chaining)。如果我们用链接法来处理冲突后边的插入是这样的这样就用链表解决了冲突问题但是如果哈希函数选不好的话可能就导致冲突太多一个链变得太长这样查找就不再是 O(1) 的了。 还有一种叫做开放寻址法(open addressing)它的基本思想是当一个槽被占用的时候采用一种方式来寻找下一个可用的槽。 这里槽指的是数组中的一个位置根据找下一个槽的方式不同分为线性探查(linear probing): 当一个槽被占用找下一个可用的槽。h(k,i)(h′(k)i)%m,i0,1,...,m−1h(k,i)(h′(k)i)%m,i0,1,...,m−1二次探查(quadratic probing): 当一个槽被占用以二次方作为偏移量。 h(k,i)(h′(k)c1c2i2)%m,i0,1,...,m−1h(k,i)(h′(k)c1c2i2)%m,i0,1,...,m−1双重散列(double hashing): 重新计算 hash 结果。 h(k,i)(h1(k)ih2(k))%mh(k,i)(h1(k)ih2(k))%m我们选一个简单的二次探查函数 h(k,i)(homei2)%mh(k,i)(homei2)%m它的意思是如果 遇到了冲突我们就在原始计算的位置不断加上 i 的平方。我写了段代码来模拟整个计算下标的过程这段代码输出的结果如下遇到冲突之后会重新计算每个待插入元素最终的下标就是Cpython 如何解决哈希冲突如不同 cpython 版本实现的探查方式是不同的后边我们自己实现 HashTable ADT 的时候会模仿这个探查方式来解决冲突。哈希函数到这里你应该明白哈希表插入的工作原理了不过有个重要的问题之前没提到就是 hash 函数怎么选 当然是散列得到的冲突越来越小就好啦也就是说每个 key 都能尽量被等可能地散列到 m 个槽中的任何一个并且与其他 key 被散列到哪个槽位无关。 如果你感兴趣可以阅读后边提到的一些参考资料。视频里我们使用二次探查函数它相比线性探查得到的结果冲突会更少。装载因子(load factor)如果继续往我们的哈希表里塞东西会发生什么空间不够用。这里我们定义一个负载因子的概念(load factor)其实很简单就是已经使用的槽数比哈希表大小。 比如我们上边的例子插入了 8 个元素哈希表总大小是 13 它的 load factor 就是 8/13≈0.628/13≈0.62。当我们继续往哈希表插入数据的时候很快就不够用了。 通常当负载因子开始超过 0.8 的时候就要新开辟空间并且重新进行散列了。重哈希(Rehashing)当负载因子超过 0.8 的时候需要进行 rehashing 操作了。步骤就是重新开辟一块新的空间开多大呢感兴趣的话可以看下 cpython 的 dictobject.c 文件然后搜索 GROWTH_RATE 这个关键字你会发现不同版本的 cpython 使用了不同的策略。python3.3 的策略是扩大为已经使用的槽数目的两倍。开辟了新空间以后会把原来哈希表里 不为空槽的数据重新插入到新的哈希表里插入方式和之前一样。这就是 rehashing 操作。HashTable ADT实践是检验真理的唯一标准这里我们来实现一个简化版的哈希表 ADT主要是为了让你更好地了解它的工作原理有了它后边实现起 dict 和 set 来就小菜一碟了。 这里我们使用到了定长数组还记得我们在数组和列表章节里实现的 Array 吧这里要用上了。解决冲突我们使用二次探查法模拟 cpython 二次探查函数的实现。我们来实现三个哈希表最常用的基本操作这实际上也是使用字典的时候最常用的操作。add(key, value)get(key, default)remove(key)具体的实现和代码编写在视频里讲解。这个代码可不太好实现稍不留神就会有错我们还是通过编写单元测试验证代码的正确性。公众号学习py最风sao的方式欢迎大家继续关注