• <知识整理>蓝书《哈希与哈希表》


    一、前言:

      有些数据不经处理是难以利用的。所谓哈希,就是通过哈希函数将这种难以简单利用的数据(比如矩阵、字符串等等)转化为可以用一个变量表示甚至可以作为数组下标的哈希值。有了哈希值,就可以实现时间复杂度近乎为常数的快速查找与匹配,更简单有效地利用一些复杂数据。

    二、字符串哈希:

      即对象为字符串的哈希。常将字符串看做一个不严格的b进制的数(有时数位上的数有可能要比b还要大),转换为10机制后再模一个数p(以便存储)得到哈希值。即定义哈希函数:

        H(C)=(c1*b^(m-1) + c2*b^(m-2) + . . . + c0*b^0)% p

          (c为字符串,m为字符串长度)

      当两字符串的哈希值相同时,我们就认为这两个字符串是一模一样的。显然这样的判断有时会有“冲突”,即相同哈希值的两个字符串可能会不同。而冲突的概率显然与p和b有关。一般来说,p的因数越多,冲突概率越大(故p一般选大素数)。

      做子串匹配时,我们要知道所有子串的哈希值。难道要用O(n^2)的复杂度全部处理出来吗?这里有一个叫做滚动哈希的优化技巧,实质是用了前缀和与递推的思想,同时我们可以用unsigned int 型,用自然溢出时对2^32取模来代替手写取模:

        设H(C,k)为字符串c前 k 个字符构成的字符串的哈希值,发现H(C,k+1)= H(C,k) * b+c[k+1]);

        主串上某一子串c[k]c[k+1]...c[k+len]的哈希值即=H(C,k+len) - H(C,k-1) * b^n; 

      这样只要预处理出b的次幂再用O(n)的时间处理出H(C,1)...H(C,m),主串所有子串的哈希值也就知道了。

      平时常应用与各种字符串匹配问题。为了进一步降低冲突概率,还可以再另处理一组哈希值,称为“双哈希”,此时取模的素数常用1e9+7和1e9+9,这两个孪生素数可以将随机数据的冲突概率降到1/(1000000009*1000000007)(当然还是防不了毒瘤出题人故意出一个卡哈希的数据,OIer与出题人的斗智斗勇永不停息......)

    三、哈希表:

      运用哈希可以将大的数据转化为较小的哈希值,同时发现如果哈希函数选取合适,那么相同哈希值的不同元素会非常少。由此提醒我们可以搞一个可以快速查询元素的结构——哈希表:

      在一个相同哈希值的域下记录相应数据。在一个哈希表中查询数据x时,算出x的哈希值h=H(x),将h域下所有的元素与x进行比较(不会很多),得出结果。

      通常用邻接链表实现哈希表,代码这里不写出了,蓝书70页写的很详细。代码中H变量没提到值,应该等于b,注意一下插入数据时先判个重。

      最后有一个小技巧:如果真实数据过大,域下记录的数据可以是模另一个素数的余数,达到“双哈希”的效果。

      

     

  • 相关阅读:
    针对小程序for循环绑定数据,实现toggle切换效果(交流QQ群:604788754)
    小程序中bindtap绑定函数,函数参数event对数据的处理
    小程序中data数据的处理方法总结(小程序交流群:604788754)
    Power OFF and ON USB device in linux (ubuntu)
    linux控制USB的绑定/解绑
    卡内操作系统COS
    Linux内核:sk_buff解析
    skb_store_bits() 和 skb_copy_bits()
    skb详细解析【转】
    TCP:WireShark分析,序列号Seq和确认号Ack
  • 原文地址:https://www.cnblogs.com/InductiveSorting-QYF/p/11219223.html
Copyright © 2020-2023  润新知