uopspop

Untitled

Jan 15th, 2022
58
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 4.67 KB | None | 0 0
  1.  
  2. Hash Function實作主要有三種:
  3.  
  4. 「Division Method」
  5. 「Multiplication Method」
  6. 「Mid-Square Method」
  7. 這三種實作,根據「隨機結果」程度排序的話(小->大):
  8.  
  9. Division Method < Multiplication Method < Mid-Square Method
  10.  
  11.  
  12.  
  13. 然而,在解題應用上,Division Method是更實用的,因為他能根據客製化邏輯,很彈性的來調整我們的hash function,非常好用。(後續單元馬上就會介紹字串的實際應用,重要觀念)
  14.  
  15. 也因此,老師不建議大家花太多時間去深入了解,為什麼Multiplication Method、Mid-Square Method比較厲害,
  16.  
  17. 因為這屬於學術領域,與我們需要的太遙遠;我們身為開發者只需知道他們隨機性大小關係就很夠用了。
  18.  
  19.  
  20.  
  21. 什麼是 Division Method?
  22.  
  23.  
  24.  
  25. hash(a) = a % b = c
  26.  
  27. Ex. hash(29) = 29 % 10 = 9
  28.  
  29.  
  30.  
  31. 輸入:a
  32.  
  33. 資料範圍/分組:b
  34.  
  35. 輸出: c
  36.  
  37.  
  38.  
  39. 其實這個式子,就是一個hash function的核心實作概念。
  40.  
  41. 其中%(取餘數)的運用有著兩種意義:
  42.  
  43.  
  44.  
  45. 1. 將資料限縮在特定範圍內
  46.  
  47. 2. 將資料進行分群
  48.  
  49.  
  50.  
  51. 比如說在JAVA中,long的範圍是 -2⁶³ ~ (2⁶³ - 1),如果我們hashed value大於小於這個值,那麼就會出現計算失真,也就是錯誤。
  52.  
  53. 因此,我們需要透過%取餘數的方式,來限縮我們最終資料的落點。
  54.  
  55.  
  56.  
  57. 什麼是 Multiplication Method?(非重點內容,可有空時再回頭看就好)
  58.  
  59.  
  60.  
  61. hash(a) = n (a * b % 1) = c
  62.  
  63. Ex. hash(29) = 100 * (29 * 0.61 % 1) = 69
  64.  
  65.  
  66.  
  67. 輸入:a
  68.  
  69. 資料範圍/分組:n
  70.  
  71. 隨機常數:b
  72.  
  73. 輸出:c
  74.  
  75.  
  76.  
  77. 如果我們要更理解這個方法,可以再拆解成下列這樣:
  78.  
  79. STEP01:拿到某個隨機產出的小數點值:(29 * 0.61 % 1)
  80.  
  81. STEP02:根據資料範圍/分組條件,將小數點值呈上n:100 * (29 * 0.61 % 1)
  82.  
  83.  
  84.  
  85. 而之所以 Multiplication Method 能產生更隨機hash值,是因為有更多的數字在乘法的時候,「交錯參與」到結果的每個數字的產生。
  86.  
  87. 但 Division Method 卻只是取餘數作為最後結果,相對隨機性小了許多。
  88.  
  89.  
  90.  
  91. 什麼是 Mid-Square Method?(非重點內容,可有空時再回頭看就好)
  92.  
  93.  
  94.  
  95. hash(a) = (a * a) % b1 / b2 = c
  96.  
  97. Ex. hash(29) = (29 * 29) % 100 / 10 = 4
  98.  
  99.  
  100.  
  101. 輸入:a
  102.  
  103. 去頭常數:b1
  104.  
  105. 去尾常數:b2
  106.  
  107. 輸出:c
  108.  
  109.  
  110.  
  111. 如果我們要更理解這個方法,可以在拆解成下列這樣:
  112.  
  113. STEP01:拿到輸入值的平方:(29 * 29) = 841
  114.  
  115. STEP02:將平方值去頭去尾,取中間數字最為最後hash值:(29 * 29) % 100 / 10 = 4
  116.  
  117.  
  118.  
  119. 而這種取平方、再取中間數字的方式,又比 Multiplication Method的隨機性更高,因為更多的數字「交錯參與」到最終結果的每個數字的產生。(越來越學術了)
  120.  
  121.  
  122.  
  123. 結論:
  124.  
  125. 不論是用哪種方式實作 Hash Function,我們的目的都是相同的:
  126.  
  127. 1. 盡最大可能避免「碰撞」的發生,因此結果值越隨機越平均則越好
  128.  
  129. 2. 限縮最終結果值的範圍,避免超出儲存空間限制
  130.  
  131. 3. 對最終結果值進行分群
  132.  
  133.  
  134.  
  135. 最後,老師這邊還是提供三種hash function完整的程式碼實作,給大家參考(一樣,建議大家有空再看後面兩種就好,不是重點):
  136.  
  137. package com.Hash;
  138.  
  139. public class hash_methods_all {
  140.  
  141. private static long hash_division(Long input_value) {
  142. int modulo_number = 1000000007;
  143. return mod(input_value, modulo_number);
  144. }
  145.  
  146. private static long hash_multiplication(Long input_value) {
  147. long range_limit = 1000000007;
  148. double random_a = 0.618033;
  149. double fraction = input_value * random_a % 1;
  150. return (long) (range_limit * (fraction));
  151. }
  152.  
  153. private static long hash_midsquare(Long input_value) {
  154. // ___XXX___ // pick 4th~6th numbers (from right to left)
  155. Long input_value_squared = input_value * input_value;
  156. Long hashed_output = input_value_squared % 1000000; // 去頭
  157. hashed_output = hashed_output / 1000; // 去尾
  158.  
  159. return hashed_output;
  160. }
  161.  
  162. private static long mod(long n, long m) {
  163. return (n%m + m) % m;
  164. }
  165.  
  166. public static void main(String[] args) {
  167.  
  168. Long input_value = 1234567890L;
  169. Long hashed_output = hash_division(input_value);
  170. System.out.println("result(division): " + hashed_output); // 104371024
  171. hashed_output = hash_multiplication(input_value);
  172. System.out.println("result(multiply): " + hashed_output); // 760370021
  173. hashed_output = hash_midsquare(input_value);
  174. System.out.println("result(midsquare): " + hashed_output); // 52 (out of 15241578750190"52"100)
  175.  
  176. }
  177.  
  178. }
  179.  
  180.  
  181.  
  182.  
  183.  
Add Comment
Please, Sign In to add comment