計算Hash沖突的概率
雖然已經很多可以選擇的Hash函數,但創建一個好的Hash函數仍然是一個活躍的研究領域。一些Hash函數是快的,一些是慢的,一些Hash值均勻地分布在值域上,一些不是。對於我們的目的,讓我們假設這個Hash函數是非常好的。它的Hash值均勻地分布在值域上。
在這種情況下,對於一個輸入集合生成的Hash值是非常像生成一個隨機數集合。我們的問題轉化為如下:
給K個隨機值,非負而且小於N,他們中至少有個相等的概率是多少?
實際上我們求這個問題的對立問題更加簡單:他們都不相同的概率是多少?無論這個對立問題的結果是多少,我們用1減去對立問題的結果就得到原問題的結果。
對於一個值域為N的Hash值,假設你已經挑選出一個值。之后,剩下N-1個值是不同於第一個值的,因此,對於第二次隨機生成不同第一個數的概率為N/N-1.
簡而言之,有N個不同的數,你第一次挑選出某個,然后繼續從N個數中挑選,那只要不是選到和第一次一樣的那個數一樣就不一樣嘍,所以概率為N-1/N。
之后就是第三次挑選,第三次挑選出的第三個數要求不同於前兩個數,所以概率就為N-1/N*N-2/N.
一般的,隨機生成K個數,他們都不相同的概率為:
計算機中,對於K很大的時候計算很麻煩,幸運的是,上面的表達式近似於
這個會更快得計算,我們如何知道這是一個好的近似。我們看一下分析過程,使用泰勒公式和epsilon-delta proof,這個誤差趨於0當N增大的時候。或者,更簡單,你可以計算2者的值然后比較他們,運行下面的python代碼,你會感覺到這個近似是多么准確:
import math N = 1000000 probUnique = 1.0 for k in xrange(1, 2000): probUnique = probUnique * (N - (k - 1)) / N print k, 1 - probUnique, 1 - math.exp(-0.5 * k * (k - 1) / N)
好的,這個奇妙的表達式作為我們每個值都不一樣的結果,然后我們用1減去得到Hash沖突的概率
這是一個 N=2^32的圖,它說明了使用32bit的Hash值的沖突概率,當Hash數是77163時,發生碰撞的可能為50%,這是有價值的。而且注意無論N區任意值都會得到一個類似S曲線的圖。
簡化表達式
這是非常有趣的,我們的表達式是1-e^-x這種形式,下面近似這僅僅在X較小的時候誤差非常小,1/10或更小:
換句話說,這個表達式非常好的近似於它自己的指數,實際上x越小,越准確,所以小的沖突概率,我們能使用這個簡化表達式
這實際上是一個非常方便的表示。因為它避免了一些在原表達式中的精度問題。浮點型數字在非常接近1的時候表示不是很好。
此外,如果N遠大於K,K和K-1並沒有什么大區別。所以我們可以更加化簡為:K^2/2N
參考: