uopspop

Untitled

Jan 15th, 2022
73
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.97 KB | None | 0 0
  1. 那在了解Division Method之後,我們來練習基礎以字串為來源資料的Hash Function的實作應用:
  2.  
  3.  
  4.  
  5. 「請將"mygod"這個字串轉成hash值?」
  6.  
  7.  
  8.  
  9. 概念一:ASCII表,每個字母(ex. t)在程式中都代表著一個數字,比如說 'A' = 65, 'z' = 122
  10.  
  11.  
  12.  
  13. 概念二:hash function要怎麼寫幾乎都行,但一個大目標是盡量地避免結果出現collision (也就是避免出現,不同input卻有相同output的狀況)
  14.  
  15. 因此對於magic number通常會使用質數(ex. 31);比如說,老師這邊想用以下邏輯將一個字串轉成hash值
  16.  
  17.  
  18.  
  19. hash("mygod") = m * (31⁴) + y * (31³) + g * (31²) + o * (31¹) + d * (31⁰)
  20.  
  21. ➤ ➤ 經過ASCII轉碼後,會變成
  22.  
  23. hash("mygod") = 109 * (31⁴) + 121 * (31³) + 103 * (31²) + 111 * (31¹) + 100 * (31⁰) = 104371024
  24.  
  25.  
  26.  
  27. 1. 在上面這個hash function的實作中,老師為了區別出不同位置的字母,所以採用了31^x。
  28.  
  29. 2. 另外為了區分出相同位置不同字母,老師再利用了ASCII表,將字母各自轉成不同的數字。
  30.  
  31.  
  32. 這邊有著一個有趣且重要的意義:我們將一個字串的「字母」+「順序」透過hash絞碎簡化成一個「數字」概念!
  33.  
  34.  
  35.  
  36. 最後,根據我們的儲存空間限制,我們必須去限縮最後結果的「落點範圍」。
  37.  
  38.  
  39.  
  40. 最現實的問題就是,每個資料型態都有他的儲存空間限制,也就是最大最小值。
  41.  
  42.  
  43.  
  44. 比如說在JAVA中,long的範圍是 -2⁶³ ~ (2⁶³ - 1),如果我們hashed value大於小於這個值,那麼就會出現計算失真,也就是錯誤。
  45.  
  46. 所以,在整個計算hash的過程中,我們必須不斷的去進行限縮落點範圍,這個步驟我們主要目的:
  47.  
  48. ➤ 避免值太大或太小,超過資料形態的範圍 (keyword: overflow)
  49.  
  50.  
  51.  
  52. 而根據前人經驗,我們大部分會使用 10^9+7 這個常數,做為我們的long的分群計算。
  53.  
  54. 因此,如果我們從概念層面來看這次的hash整個過程,目前就會變成
  55.  
  56.  
  57.  
  58. module_number = 10^9+7 = 1000000007
  59.  
  60. hash("mygod") % module_number = 104371024
  61.  
  62.  
  63.  
  64. 然而關於%,還有一個地方要去顧:
  65.  
  66. 在程式語言中,如果我們對一個負數 -5 % 3 = -2,結果是一個負數。
  67.  
  68. 但這樣是不正確的,在數學上 -5 % 3 = 1,結果要是0以上,因此我們需要下列的module方法,來適應程式語言的數學特性:
  69.  
  70. 如果 num % mod 之後是負的
  71. 所以 + mode 把它轉回正的
  72. 但如果 num % mod 原本就是正的,再 + mod 之後又有可能太大超出mod的範圍,所以再一次 % mod
  73. private long mod(long num, long mod) {
  74. return ( num % mod + mod) % mod;
  75. }
  76. 那麼,最後我們則有:
  77.  
  78.  
  79.  
  80. String source = "mygod";
  81.  
  82. int hashed_value = hash(source);
  83.  
  84. int hashed_moded_value = mode(hashed_value);
  85.  
  86.  
  87.  
  88. 實作範例:
  89.  
  90. package com.Hash;
  91.  
  92. public class hash_basic {
  93.  
  94. private static long hash(String str) {
  95. int magic_nubmer = 31; // you can pick other prime number
  96. int module_number = 1000000007;
  97. long hashedbucket = 0;
  98. for (int i = 0; i < str.length(); i++) {
  99. /** step01: move ALL left each round **/
  100. hashedbucket *= magic_nubmer; // leverage multiplication to show different char position
  101. hashedbucket = mod(hashedbucket, module_number);
  102. /** step02: add the newly right-most char **/
  103. hashedbucket += str.charAt(i); // leverage ASCII chart to convert char into int
  104. hashedbucket = mod(hashedbucket, module_number);
  105. /** stepall: use % to categorize & avoid overflow in every step **/
  106. }
  107.  
  108. return hashedbucket;
  109. }
  110.  
  111. private static long mod(long n, long m) {
  112. return (n%m + m) % m;
  113. }
  114.  
  115. public static void main(String[] args) {
  116. String str = "mygod";
  117. long hashed_moded_result = hash(str);
  118. System.out.println("result: " + hashed_moded_result); // 104371024
  119. }
  120.  
  121. }
  122.  
  123.  
  124.  
  125.  
  126.  
  127.  
  128.  
  129.  
  130.  
  131.  
  132.  
Add Comment
Please, Sign In to add comment