元素集合可以轉換為正整數集合,因此問題可以寫成:給定範圍 ,已使用之數字集合為 ,最簡單的演算法就是排除
從中隨機取一個元素
問題 [local-0]
然而排除已使用元素是固定成本,在已使用元素會變多的情況下更是越來越大的成本。隨機抽一個,再查看有沒有撞上已經使用的位置反而更有效。但這樣做的界線到底在哪裡?
幾何分布 [local-1]
對於空間大小 與已使用的 ,隨機抽一個位址命中未使用元素的機率是
假設每次抽樣互相獨立,那「抽到第 次才第一次成功」服從幾何分布
連續 次都失敗(選到已使用的位置)的機率是 ,期望次數是
所以我們可以看到 只佔 一小部分時,期望次數幾乎是常數, 時也只是2次,跟排除法的 差距明顯。要等到 幾乎為 時,這才開始稱得上成本
計算重試上限 [local-2]
隨 遞減趨近 ,但對任何有限的 都不等於 ,也就是不存在有限次數可以保證我們抽到未使用的數字。所以這裡要找的不是「幾次一定會中」,而是「願意接受多大的失敗機率」
給定可以接受的失敗機率 tr-notes 取 ,我們想找出滿足 的最小
先對兩邊取 , 單調遞增所以不等號方向不變
根據Logarithm power rule可以得出
時 ,所以同除要翻轉不等號
第二個等號來自分子分母同乘 ,讓兩邊都寫成正數。取ceiling就是可拿來做嘗試次數的最小
但計算 太麻煩了,所以實作上用 當上限這裡 ,而 就是上面的期望次數。這個做法是因為如果把分母展開成無限級數注意收斂條件
時每一項都是正的,因此可以看出 被砍掉的高次項正好說明了高估多少
分母變大則整體變小,所以 ,也就是 大於等於 總是成立。因此這是安全的高估,代價是最壞情況多重試幾次,但讓我們不必計算 在 時數值上也不穩,這是另一個不採用的理由
最後這個上限還要跟 取 min。期望次數 本身其實永遠不會超過 (最壞的 時剛好等於),但 可能會超過: 時就有 。既然這時候成本已經比掃過整個空間還高,應該放棄然後退回過濾再抽取的演算法
結論 [local-3]
我們分析了抽取的上限是怎麼推導出來的,並且計算超過上限就退回一開始的排除法。所以最壞情況是 而不是不會停;另外空間真的滿了會直接報錯,這也是為什麼上面的分析不涉及
這個演算法用在 raco tr next 的 --random 功能上