一种新的哈希算法,欢迎拍砖

romandion 2010-06-24 01:11:28
好久没有在论坛发表帖子,最近研究一种哈希算法,偶有所得,探讨下。
http://blog.csdn.net/romandion/archive/2010/06/23/5689160.aspx

哈希在查找算法中,可以算是最高效,不过它受哈希函数和冲突解决函数限制,对于普适性的场景具有很大的限制。在通用传输平台中,用来解决海量会话,句柄,线程的定位确有先天的优势。因为这些场景的值,具有很高的连续性。基本上不会出现上一个是1,而下一个却变成222222。而且,在增删的场景下,不象树以及其他结构,需要对管理器进行锁定,可以实现无锁操作。

哈希算法以及原理就不需要介绍了。这里关键的是要设计一种算法,来处理值比较聚集情况下,一种哈希的冲突解决办法。我们知道,哈希值可以假定为一种无符号32位整数,通常都是这样。对于H(key)的设计来说,要解决算法简单,而且耗时较小,不然性能必然会很大折扣。另外还必须减少冲突。对于一个长度为M的哈希表,必须将N个元素尽可能聚集在一起,避免溢出。当A=N/M越大,造成的空间浪费也越大。

在APR的哈希实现中,使用取模的方式,模数为2^N - 1。当发生冲突时,就扩展哈希表,新模数为2^(N+1) -1。这个模数好处,比较明显,直接用KEY & MOD就能得到地址,算法简单,而且快速。不过问题很明显,冲突的概率很大。

现在,我们仔细研究下,在哈希值聚集比较明显的情况。

1、哈希值如果聚集的情况,那么他们会出现多个聚集带,针对不同聚集带采用不同的H函数,将减少M的值。

2、当N越大的事情,M将增加,冲突将增加,我们增加定位的次数,将被允许。不过,次数必须受到限制,否则将和树的性能相类似。

3、如果值比较密集的情况下,那么低比特位的值会比较集中。而高比特位的值会相对一致。

4、当一个冲突无法解决情况,我们要对原来值进行分裂,那么必须保证分裂出来的值尽可能的少。

5、在很糟糕的情况下,哈希值呈现等距分布,比如1M ,2M ...,那么我们会出现频繁分裂的情况,必须予以解决。

我的想法是这样的,将32位分为10 + 10 + 12三个段,每个段的比特位就成这样了,A段[0-->9],B段[10-->19],C段[20-->31]。基于我们原先假定哈希值密集的情况。而且4K是很多物理页的基本尺寸,有底层的优势。每个段,都会存在掩码,而且这个掩码可能发生变化,这个变化是扩展性的。比如原来是 00110000 ,后面就变成了00111000。

在一个已经存在的,均匀分布的哈希表中,新增一个哈希值,引起冲突,那么这个冲突其实只会跟其中一个冲突。那么,我们比较下这2个冲突的哈希值,很容易发现,究竟在那个段,以及哪个掩码是不一样。于是,我们只要简单的修改下那个段的掩码,使得这2个哈希值不一致。但糟糕的是,掩码的变化,使得很多已经存在的哈希值,必须重新定位到新分裂出来的桶中。而段掩码的选择,必然影响分裂到新桶中哈希值的多少。分裂出来的越多,那么性能就越低,这种情况有点象磁盘整理,是很恐怖的事情。针对这种情况,我们必须增加一个计数器,这个计算器记录每个比特位,含有多少个哈希值。那么新掩码生成时,在段的掩码中选择一个哈希值最少的比特位。那么需要分裂出来的哈希值就少很多。

我们知道,哈希表的值是很稀疏的,如果要遍历所有的节点,来判断是否需要分裂,也是件很恐怖的事情。所以,我们必须为这个哈希值增加一个后续哈希值的指针。当新增哈希值的时候,直接推送入栈。删除,只要删除哈希值所挂接的节点,而不需要删除指针,如果相邻的多个指针被删除,才需要进行合并。因为通常这种情况发生的情况很少。

如果假设,已经有1M被均匀分布在哈希表,新增的哈希值,导致分裂,会出现什么状况呢?所有的掩码比特位都被充满了,掩码实际上已经失去了作用。原来在该比特位为1的哈希值都要被重新定位到新分裂出来的值,理论上,分配的空间接近原来已经分配的空间。这是很恐怖的事情。这种情况,将导致插入效率急剧下降。而最好的方式,就是只为新插入的哈希值分配空间。那么新的问题就是,原来已经存在的哈希值不在新的掩码范围内,导致查找失败。因此,我们必须保存掩码的所有的历史。查找的时候,从最新的掩码开始,如果没有找到,那么原先保存在旧掩码节点的哈希值就需要被分裂出来。如此策略,会存在2种情况,一种是查找失败的事情,按照掩码的历史往前回溯,找到正确的哈希值,将该哈希值分裂到新的节点中。这种分裂,只要执行一次,就能适配到最新的掩码。另外一种情况,是新增的哈希值,按照新的掩码,跟旧的掩码冲突,那么同样需要将旧哈希值分裂到新的节点中。这种策略,避免新增一个掩码,需要将大量的哈希值分裂到新的节点中。

单个哈希值独占一个段的情况将会存在。是否存在合适算法或者策略来收缩这种空间浪费呢?我们将这个段的比特位清零,那么,这个比特位上,所有的值必须解决冲突,是个大工程。不过我们可以解决一个问题,如果某个段只有值,那么我们将这个段指针指向值,而不是缓冲区。那么对稀疏的哈希以及等步长的哈希有很大的空间改善。当一个哈希值被删除的时候,可能整个段只有它一个哈希值,那么这时候就必须进行收缩,回收内存,将该哈希值,挂接到父节点中。
...全文
96 回复 打赏 收藏 转发到动态 举报
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

33,007

社区成员

发帖
与我相关
我的任务
社区描述
数据结构与算法相关内容讨论专区
社区管理员
  • 数据结构与算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧