JAVA 實現 - 雜湊表

chuangzhou發表於2024-07-28

雜湊演算法 String.hashCode

public static void main(String[] args) {
    String  str1 = "abc";
    String str2 = "bca";

    int hash = 0;
    for (int i = 0; i < str2.length(); i++) {
        char c = str1.charAt(i);
        System.out.println((int)c);

        hash += c;
    }
    System.out.println(hash);
}

以上hash值是將每個字元的值相加得到一個hashcode,但問題是"abc" 與 "cba" 的hashcode 就會一致。如何解決?
可以給前兩位字元都乘以一個權重,如下
a * 100 + b * 10 + c
b * 100 + c * 10 + a

實現如下:

public static void main(String[] args) {
    String str1 = "abc";
    String str2 = "bca";

    System.out.println("str1 => String.hashCode:" + str1.hashCode());
    System.out.println("str2 => String.hashCode:" + str2.hashCode());
    int hash = 0;
    for (int i = 0; i < str1.length(); i++) {
        char c = str1.charAt(i);
        System.out.println((int) c); 
        hash = hash * 10 + c;  //loop1: 0+a, loop2: (0+a)*10+b, lopp3: ((0+a)*10+b) * 10 + c <=> a*100 + b*10 +c
    }
    System.out.println(hash);
}

還可以進一步最佳化, 將 hash * 10 改為 乘以一個質數 如31 ,但是為什麼是指數那?

public static void main(String[] args) {
    String str1 = "abc";
    String str2 = "bca";

    System.out.println("str1 => String.hashCode:" + str1.hashCode());
    System.out.println("str2 => String.hashCode:" + str2.hashCode());
    int hash = 0;
    for (int i = 0; i < str1.length(); i++) {
        char c = str1.charAt(i);
        System.out.println((int) c);
        hash = hash * 31 + c;  //loop1: 0+a, loop2: (0+a)*10+b, lopp3: ((0+a)*10+b) * 10 + c <=> a*100 + b*10 +c
    }
    System.out.println(hash);
}

輸出:

str1 => String.hashCode:96354
str2 => String.hashCode:97344
97
98
99
96354

此時輸出的hashcode 就是 String 類的實現,還可以進一步最佳化: 將乘法運算轉換為 左移位運算,因為位運算的效率比乘法高,32為 2 的 5次方,因此可以左移5位

public static void main(String[] args) {
    String str1 = "abc";
    String str2 = "bca";

    System.out.println("str1 => String.hashCode:" + str1.hashCode());
    System.out.println("str2 => String.hashCode:" + str2.hashCode());
    int hash = 0;
    for (int i = 0; i < str1.length(); i++) {
        char c = str1.charAt(i);
        System.out.println((int) c);
        hash = (hash << 5) - hash + c;  //loop1: 0+a, loop2: (0+a)*10+b, lopp3: ((0+a)*10+b) * 10 + c <=> a*100 + b*10 +c
    }
    System.out.println(hash);
}

相關文章