【问题标题】:How to calculate the hash code of a string by hand?如何手动计算字符串的哈希码?
【发布时间】:2010-09-25 20:14:44
【问题描述】:

我想知道如何手动计算给定字符串的哈希码。我知道在 Java 中,您可以执行以下操作:

String me = "What you say what you say what?";  
long whatever = me.hashCode();

这一切都很好而且花花公子,但我想知道如何手工完成。我知道计算字符串哈希码的给定公式类似于:

S0 X 31 ^ (n-1) + S1 X 31 ^ (n-2) + .... + S(n-2) X 31 + S(n-1)  

其中S表示字符串中的字符,n表示字符串的长度。然后使用 16 位 unicode,字符串 me 中的第一个字符将被计算为:

87 X (31 ^ 34)

但是,这会产生一个非常大的数字。我无法想象像这样将所有角色加在一起。那么,为了计算最低位的 32 位结果,我该怎么办?上面的long等于-957986661,我不知道如何计算?

【问题讨论】:

    标签: java hash


    【解决方案1】:

    看看java.lang.String的源码。

    /**
     * Returns a hash code for this string. The hash code for a
     * <code>String</code> object is computed as
     * <blockquote><pre>
     * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
     * </pre></blockquote>
     * using <code>int</code> arithmetic, where <code>s[i]</code> is the
     * <i>i</i>th character of the string, <code>n</code> is the length of
     * the string, and <code>^</code> indicates exponentiation.
     * (The hash value of the empty string is zero.)
     *
     * @return  a hash code value for this object.
     */
    public int hashCode() {
        int h = hash;
        int len = count;
        if (h == 0 && len > 0) {
            int off = offset;
            char val[] = value;
            for (int i = 0; i < len; i++) {
                h = 31*h + val[off++];
            }
            hash = h;
        }
        return h;
    }
    

    【讨论】:

    • 我明白了基本的想法(我可以计算小字符串),但是当字符串变大时,我不确定该怎么做。
    • @user458346,字符串的大小并不重要。这就是使用循环的价值,不管循环多长,它确实会变得更复杂。
    • 偏移是从哪里开始的?
    【解决方案2】:

    大多数此类散列函数计算散列值modulo 一些大数(例如大素数)。这避免了溢出并将函数返回的值范围保持在指定范围内。但这也意味着无限范围的输入值将从一组有限的可能值(即[0,模数))中得到一个哈希值,因此会出现哈希冲突的问题。

    在这种情况下,代码如下所示:

       public int hash(String x){
            int hashcode=0;
            int MOD=10007;
            int shift=29;
            for(int i=0;i<x.length();i++){
                hashcode=((shift*hashcode)%MOD+x.charAt(i))%MOD;
            }
            return hashcode; 
        }
    

    读者练习:

    请参阅 java.util.String 的 hashCode 函数的代码。你能明白为什么它没有明确地使用模数吗?

    【讨论】:

    • 我看不到...你能解释一下吗?
    • @jjczopek:注意x%2^n = x&amp;(2^n-1)。因此,如果您进行算术模 2^n,您只需要保留值的最后 n 位,丢弃任何更高位。现在想想当你只使用int 来代表你的价值时会发生什么。您执行的任何算术运算都会导致仅剩下最后 32 位。瞧,你的算术模数是 2^32。
    • 对。你怎么没看到jjczopek >_<.>
    【解决方案3】:

    下面的语句会找到字符串hashCode

    String str="Hi";
    
    int a = str.hashCode();//returns 2337
    

    让我们检查一下它的计算方式

    HashCode = s[0]*31(n-1) + s[1]*31(n-2) + .. s(n-2)

    众所周知,位置0的字符是H,位置1的字符是i,字符串长度是2。

    ==> H*31(2-1) + i*31(2-2)

    众所周知,H的ASCII码是72,i是105,意思是,

    ==> 72 * 31 + 105 * 1(任何幂 0 为 1)

    ==> 2232 + 105 = 2337

    来源:https://www.tutorialgateway.org/find-string-hashcode-in-java/

    【讨论】:

      猜你喜欢
      • 2012-07-12
      • 2013-01-16
      • 2011-02-13
      • 1970-01-01
      • 2013-02-16
      • 2011-11-02
      • 2011-07-20
      • 2012-08-23
      • 2016-09-04
      相关资源
      最近更新 更多