闲聊哈希表 (下)

Sina WeiboBaiduLinkedInQQGoogle+RedditEvernote分享




上回我们说到,在Hash表的建立时,会发生Hash值冲突的情况。实际上,如果记录Hash值的范围多于Hash表的条数,根据抽屉原理,一定会发生冲突。对于冲突的处理,我们一般有这几种方法:

1,              对Hash表中每个Hash值建立一个冲突表,即将冲突的几个记录以表的形式存储在其中;

2,              改变规则重新计算一次Hash值;

3,              建立一个公用的区域存放冲突的表项;

在工程上,考虑到实现算法的复杂度,方法1用得是最多的。对于方法1,又有两种不同的实现,一种方法是对每个Hash值,建立一个Hash桶(Bucket),桶的容量是固定的,也就是只能处理固定次数的冲突,如1048576个Hash桶,每个桶中有4个表项(Entry),总计4M个表项。另一种方法是,不限制Hash桶的容量,以链表形式将冲突的记录挂接在一个Hash桶中。

这两种实现各有什么利弊呢?首先,让我们看看第一种实现:

在这种情况下,由于Hash桶容量的限制,所以,有可能发生Hash表填不满的情况,也就是,虽然Hash表里面还有空位,但是新建的表项由于冲突过多,而不能装入Hash表中。不过,这样的实现也有其好处,就是查表的最大开销是可以确定的,因为最多处理的冲突数是确定的,所以算法的时间复杂度为O(1)+O(m),其中m为Hash桶容量。

而另一种实现,由于Hash桶的容量是无限的,因此,只要没有超出Hash表的最大容量,就能够容纳新建的表项。但是,一旦发生了Hash冲突严重的情况,就会造成Hash桶的链表过长,大大降低查找效率。在最坏的情况下,时间复杂度退化为O(n),其中n为Hash表的总容量。当然,这种情况的概率小之又小,几乎是可以忽略的。

Hash表的一个应用例子,是在网关(Gateway)中。以网络防火墙为例,它是根据源IP,目的IP,源端口,目的端口,协议号构成的五元组来标识一条网络数据流的,并且根据五元组来建立会话表项(session entry)。为了查找便捷,一般都使用Hash表来实现这个会话表,以提高转发的效率。事实上,对于大量表项的查找,逐项查找是不允许的,一般都使用Hash表来实现。不夸张的说,我们可以说,在你生活的每一天,都免不了同Hash表打交道,比如,查字典。

最后,我想说,数据结构的万紫千红中,我独爱Hash表这一种。

(4个打分, 平均:5.00 / 5)

雁过留声

“闲聊哈希表 (下)”有11个回复

  1. ABCD 于 2010-03-07 12:45 下午

    这三篇看起来真像是混积分的

  2. 陈怀临 于 2010-03-07 1:06 下午

    咔咔。反正我期盼帅帅下面的文章是:Atom vs Arm系列,而非来个闲聊二叉树的广度优先算法。。。厚积薄发。帅帅,你能行。You can do it.

  3. sigh 于 2010-03-08 5:48 上午

    其实HASH本来是一个很有技术含量的话题的….

  4. sigh 于 2010-03-08 5:50 上午

    建议弯曲的文章分类可以更细一点

  5. kevin 于 2010-03-08 9:07 上午

    为什么我这么喜欢线性表呢

  6. efgh 于 2010-03-12 12:19 上午

    线性表 cache miss 少?

  7. niels 于 2010-03-12 12:31 上午

    不知道有哪家的产品里flow table不是用哈希表实现的。比如在某些允许flase positive的情况下用bloom filter实现,应该可以省不少memory

  8. Panabit 于 2010-03-12 1:51 上午

    开源的Packet Filter(PF)使用Tree来实现,虽然可以BOUND住最坏性能,但是性能不好,特别是插入和删除的时候,会严重pollution cache。

  9. Multithreaded 于 2010-03-12 9:34 上午

    #5, 为什么我这么喜欢线性表呢

    如何构建一百万个TCP flow 的线性表哪?
    表中每一个项至少有:(S_IP, D_IP, S_port, D_port) 四元组.

  10. 笑生 于 2011-01-05 12:33 上午

    1000w个随机五元组hash到23个bit位宽,二次hash到11bit,桶深32,冲突率怎么算呢?-,- 概率没学好。

  11. dongbinghua 于 2011-09-24 1:41 上午

    深入浅出