雜湊演算法 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);
}