发布时间:2025-05-27 15:19:09 点击量:
HASH GAME - Online Skill Game GET 300【摘要】 @[TOC]前言font color = black上一篇文章我们学习了STL中unordered系列容器的使用,并且提到,unordered系列容器的效率之所以比较高(尤其是查找),是因为它底层使用了哈希结构,即哈希表。那这篇文章,我们就来学习一下哈希表1. 哈希的概念font color = black顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找一个...
font color = blue从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止,将新插入的值放到该空位置。即$H_i$ = ($H_0$ + $i$ )% m,i=1,2,3,4...$H_0$是通过散列函数Hash(x)对元素的关键码 key 进行计算得到的位置,m是表的大小,$H_i$是向后探测的位置font color = black为什么加完i还要模m呢,因为一直加的话可能会超过表长,这时就要回到开头往后进行探测了
font color = #000066线性探测优点:实现非常简单,线性探测缺点:一旦发生哈希冲突,所有的冲突连在一起,容易产生数据“堆积”(我向后探测放到后面的空位置就占用了别的位置,其它key定位到这个位置也需要再向后探测),即:冲突值占据了可利用的空位置,使得寻找某关键码的位置需要许多次比较(从冲突位置可能要向后查找多次),导致搜索效率降低。可以认为闭散列本质是就是一种零和游戏
font color = #000066散列表的载荷因子定义为:α =填入表中的元素个数/散列表的长度α是散列表装满程度的标志因子。α越大,表明填入表中的元素越多,产生冲突的可能性就越大;反之,α越小,表明填入表中的元素越少,产生冲突的可能性就越小。实际上,散列表的平均查找长度是载荷因子α的函数,只是不同处理冲突的方法有不同的函数。对于开放定址法,荷载因子是特别重要因素,应严格限制在0.7-0.8以下。超过0.8,查表时的CPU缓存不命中(cache missing)按照指数曲线上升。所以当负载因子超过规定值就要扩容。
font color = black是不是还没有啊,刚才的代码解决了扩容和size为0情况的处理。但是还有一个问题:font color = #000066就是我们使用resize扩容之后哈希表的size改变了,而我们用的哈希函数是除留余数法Hash(key) = key% size,那size变了,映射关系也就变了扩容之后原来表里面已经插入的值,它现在新的散列地址如果还用之前的,可能就不对了。
font color = #000066空间利用率低、冲突频率高:开放定址法容易产生冲突,特别是当哈希表的负载因子较大时,即哈希表的装满程度更高。这会导致性能下降,因为冲突的数量会增加,导致查找的效率降低。而一旦减小负载因子,又会导致频繁扩容,空间利用率低。聚集问题:开放定址法在处理冲突时,有时会出现聚集问题。聚集是指数据项在哈希表中被连续地存储在相邻的位置上,这样会导致冲突更加频繁,并且会造成某些位置的利用率低而其他位置的利用率高的情况。
font color = #000066怎么优化呢?我们上面的写法,遍历旧表,依次把每个哈希桶里面的数据重新插入到新表newht里面,虽然我们遍历用了引用,但是它里面调inert的时候,在insert里面还是会拿旧表里面每个结点的_kv去重新开结点然后插入,最后还要一个一个结点释放旧表。所以我这里想这样优化一下:我想直接把旧表的结点直接拿下来插入到新表里面,这样即不用开新结点,最终交换之后也不用释放旧表的结点。那这样的话我们就不去复用insert了,自己去搞
font color = black我们上面用两种方式实现了哈希表(当然接口可能没有实现特别完整),但是我们上面的实现哈希表里面存的都是整型,而我们的哈希函数用整型进行计算刚好是比较好的(比如我们上面用的是除留余数法)。但是如果是其它类型,要是浮点型或者char类型,还比较好处理,因为可以强转,但是,如果是除此之外的其它类型,比如string,或者其它的自定义类型,我们的程序还能很好的处理吗?
font color = #000066对于哈希表的查找,如果我们考虑最坏的情况的话,是O(N),即在插入的元素里面,大部分的值都冲突到一个位置,被放到同一个桶里面。但是,这种最坏的情况几乎不会出现。因为我们插入的过程还会不断扩容,而扩容的过程旧表的值重新散列到扩容之后的新表里面,它的冲突值是会不断减少的。另外我们的负载因子也在控制嘛,像我们上面设置负载因子为1,平均情况就是每个哈希桶上面挂一个值再插入就要扩容了。所以如果按平均情况的线),这是很快的。