隨機打亂數組算法、蓄水池算法


1.隨機打亂數組(洗牌算法)

  分析洗牌算法正確性的准則:產生的結果必須有 n! 種可能,否則就是錯誤的。這個很好解釋,因為一個長度為 n 的數組的全排列就有 n! 種,也就是說打亂結果總共有 n! 種。算法必須能夠反映這個事實,才是正確的。

代碼:

def shuffleArr(arr):
    l = len(arr)
    for i in range(l):
        rand = random.randint(i,l-1)
        arr[i],arr[rand] = arr[rand],arr[i]
    print(arr)

arr = [1,2,3,4,5]
shuffleArr(arr)

  

2.蓄水池算法

應用場景:長度未知的海量數據流中隨機等概率抽取一個數據

算法過程:

  假設數據序列的規模為n,需要采樣的數量的為k。

  首先構建一個可容納k個元素的數組,將序列的前k個元素放入數組中。

  然后從第k+1個元素開始,以\(\frac{k}{n}\)的概率來決定該元素是否被替換到數組中(數組中的元素被替換的概率是相同的)。 當遍歷完所有元素之后,數組中剩下的元素即為所需采取的樣本。

證明過程:

對於第i個數(\(i≤k\))。在k步之前,被選中的概率為1。當走到第k+1步時,被k+1個元素替換的概率 = \(k+1\)個元素被選中的概率\(\times\) i被選中替換的概率,即為\(\frac{k}{k+1} \times \frac{1}{k}\)。則被保留的概率為\(1-\frac{1}{k+1}=\frac{k}{k+1}\)。依次類推,不被k+2個元素替換的概率為\(1 - \frac{k}{k + 2} \times \frac{1}{k} = \frac{k + 1}{k + 2}\)。則運行到第n步時,被保留的概率 = 被選中的概率 * 不被替換的概率,即:

\(1 \times \frac{k}{k + 1} \times \frac{k + 1}{k + 2} \times \frac{k + 2}{k + 3} \times … \times \frac{n - 1}{n} = \frac{k}{n}\)

對於第j個數(\(j>k\))。在第j步被選中的概率為\(\frac{k}{j}\)。不被j+1個元素替換的概率為\(1 - \frac{k}{j + 1} \times \frac{1}{k} = \frac{j}{j + 1}\)。則運行到第n步時,被保留的概率 = 被選中的概率 \(\times\)不被替換的概率,即: \(\frac{k}{j} \times \frac{j}{j + 1} \times \frac{j + 1}{j + 2} \times \frac{j + 2}{j + 3} \times ... \times \frac{n - 1}{n} = \frac{k}{n}\) 所以對於其中每個元素,被保留的概率都為\(\frac{k}{n}\).

代碼:

import random
def ReservoirSamplingTest(k):
    N = 10
    pool = [i for i in range(N)]
    result = pool[:k]
    for i in range(k,N):
        r = random.randint(0,i+1)
        if r < k:
            result[r] = pool[i]
    return result

res = ReservoirSamplingTest(4)
print(res)

  

參考文獻:

【1】洗牌算法深度詳解 - 打亂數組 - 力扣(LeetCode)

【2】蓄水池采樣算法(Reservoir Sampling) - alfred_zhong - 博客園


免責聲明!

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



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