C 向下调整哈希表的大小有意义吗?什么时候?

C 向下调整哈希表的大小有意义吗?什么时候?,c,resize,hashtable,load-factor,C,Resize,Hashtable,Load Factor,我的哈希表实现有一个函数,可以在负载达到70%左右时调整表的大小。我的哈希表是通过单独的冲突链接实现的 我应该在任何时候调整哈希表的大小,还是让它保持原样,这有意义吗?否则,当负载为70%时,如果我增加大小(几乎是原来的两倍,实际上我是这样做的:),那么当负载为30%或更低时,我是否应该减小它的大小?如果内存很便宜,就别管它了。如果内存很昂贵,请按照您的建议使用癔症调整大小。完成后,对结果进行分析,以确保其性能良好,并且没有做过愚蠢的事情。您编写的哈希表是用于一般用途,还是有特定用途?我建议不要

我的哈希表实现有一个函数,可以在负载达到70%左右时调整表的大小。我的哈希表是通过单独的冲突链接实现的


我应该在任何时候调整哈希表的大小,还是让它保持原样,这有意义吗?否则,当负载为70%时,如果我增加大小(几乎是原来的两倍,实际上我是这样做的:),那么当负载为30%或更低时,我是否应该减小它的大小?

如果内存很便宜,就别管它了。如果内存很昂贵,请按照您的建议使用癔症调整大小。完成后,对结果进行分析,以确保其性能良好,并且没有做过愚蠢的事情。

您编写的哈希表是用于一般用途,还是有特定用途?我建议不要为了一般的实现而调整尺寸。这将使您的表保持简单,并在表经常被填满或清空的情况下防止内存波动。如果最终遇到需要减小哈希表大小的情况,请在该时间点进行扩展。

如果具有高质量的哈希函数,则哈希表不必具有素数长度(请参阅)。您可以将它们设为二的幂,这大大加快了索引计算


为什么这与这个问题有关?因为当您缩小两个哈希表的幂时,您可以将所有条目保留在下半部分,只需将链表附加到slot
i
(从上半部分开始)在slot
i-n/2

中的链表上,第一个想法:增加哈希表的唯一原因是,如果冲突太多,哈希表性能会降低。当表的负载超过70%时增加它是防止这种情况发生的一个很好的经验法则,但这只是一个经验法则。更好的方法是跟踪冲突的数量,只有当冲突超过某个限制或达到某个冲突比率时,才增长哈希表。毕竟,为什么要增加一个加载率为90%但没有一次冲突的哈希表?这没有好处

第二个想法:缩小哈希表的唯一原因是为了节省内存,但缩小哈希表可能会增加冲突的数量,从而降低查找性能。这是一个经典的速度与内存的权衡,为什么你要自己解决呢?把它留给使用你的代码的人。不要自己收缩,而是提供一种收缩方法。如果需要低内存使用率,那么无论谁使用您的代码都可以定期调用shrink。如果需要最大性能,则无论是谁使用您的代码都不应调用shrink。其他每个人都可以使用某种启发式方法来决定是否以及何时调用shrink

第三个想法:当增长或收缩时,始终以这样一种方式增长/收缩,即在运行后保证一定的负载系数。例如,在增长时,始终保持增长,使之后的荷载系数为50%;在收缩时,始终保持收缩,使之后的荷载系数为70%。当然,这与冲突的数量无关,因此在增长/收缩后立即添加元素可能会导致哈希表再次增长,但这是不可避免的,因为模拟增长/收缩的效果通常代价太高。此外,一旦没有进一步的修改计划,通常会调用shrink,因此它应该节省内存,而不是避免将来再次增长


最后一个想法:对于您所做的每一个决定,您都会使哈希表在某些情况下更好,而在其他情况下更糟。如果您知道如何使用哈希表,这不会是问题。然而,如果你不这样做,通常你不这样做,为什么要自己做这些决定呢?只要授权他们就行了。允许代码的用户自定义所有小细节,例如增长或收缩的程度,方法是在创建哈希表时设置所有这些因素,或者允许哈希表具有委托函数(在不确定如何操作时始终可以询问的回调函数)。这样,您的代码的每个用户都可以自定义您的代码,即使是在运行时,也可以根据需要自定义代码。

+1这是一个非常好的链接。谢谢分享。你关于缩小和保留另一半的观点也是有道理的。