蓄水池抽樣算法


問題定義

給你一個長度為N的鏈表。N很大,但你不知道N有多大。你的任務是從這N個元素中隨機取出k個元素。你只能遍歷這個鏈表一次。你的算法必須保證取出的元素恰好有k個,且它們是完全隨機的(出現概率均等)。

求解

蓄水池抽樣算法:

該算法是針對從一個序列中隨機抽取不重復的k個數,保證每個數被抽取到的概率為k/n這個問題而構建的。做法是: -
首先構建一個可放k個元素的蓄水池,將序列的前k個元素放入蓄水池中。
然后從第k+1個元素開始,以k/n的概率來決定該元素是否被替換到池子中。 當遍歷完所有元素之后,就可以得到隨機挑選出的k個元素。復雜度為O(n).

其偽代碼如下:

Init : a reservoir with the size: k

        for    i= k+1 to N

            M=random(1, i);
            if( M < k)
                 SWAP the Mth value and ith value
       end for

證明每個數被取到的概率為k/n:

      1. 對於第i個數(i<k),在前k步被選中的概率是1, 從第k+1步開始,i不被選中的概率為k/k+1,那么讀到第n個數時, 第i個數(i<k)被選中的概率 = 被選中的概率 * 以后每一步都不被換走的概率,即
        1 * k/k+1 * k+1/k+2 n-1/n = k/n

      2. 對於第j個數(j>=k)被選中的概率為: 在他出現時被選中的概率 * 在他出現以后不被換走的概率,即: 
        k/j * j /j+1 。。。n-1/n = k/n

      3. 綜上得證。

 



免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM