撲克洗牌的算法比較

洗牌
計算機科學二級

Alice和Bob想為他們的撲克俱樂部制作一臺洗牌機。問題是,他們提出了不同的算法,因此無法決定應用哪一種算法:

愛麗絲的算法思路:從左到右依次,每張牌只和位于右邊的任何牌交換位置。
鮑勃的算法思路:從左到右一次,每張牌與任何其他牌交換位置。
誰的算法更好,或者這真的很重要嗎?

運用可視化直觀地看到兩種思路的算法比較:

brilliant_card_shuffleFigure_1.png

答案可能一開始是反直覺的。為什么Bob的算法不好?難道它不能生成所有的排列組合嗎?答案是肯定的,它可以生成所有的排列組合,但不是均勻的。總共有多達 n^n = n的n次方移動方式, 但問題在于,n副牌的排列也只有n!個排列組合的方式。

由于n^n不能整除n!,意味在一般情況下,并不是所有的排列組合都有同等的機會產生。

現在我們確信鮑勃的算法是壞的,但它有多壞呢?注意到了,如果一張牌被換到左邊,它就不能再往左走了!

還不服氣嗎? 讓數據來說話。

上圖左邊是Alice的算法,右圖是Bob的算法。
x軸是數字,y軸是它經過算法后最終的位置。越亮的單元格,數字最終出現在那個位置的頻率越高。正如你所看到的,大部分的數字最后都在它的左邊!

如果你對可視化是如何生成的感興趣,這里是代碼。

from random import randint
import matplotlib.pyplot as plt

n = 1000 #模擬1000次洗牌
x_data = []
y_data = []
# start simultion for distributed permutations
for simulation in range(n):
    # perfectly sorted array
    arr = [x + 1 for x in range(n)]
    for i in range(n):
        r = randint(0, i) # correct way

        # swap two elements
        arr[r], arr[i] = arr[i], arr[r]

    # collect result
    for i in range(n):
        x_data.append(arr[i])
        y_data.append(i+1)
# end simulation

# plot
fig, axs = plt.subplots(ncols = 2, sharey=True, figsize=(14, 6))
fig.subplots_adjust(hspace=0.5, left=0.07, right=0.93)
hb = axs[0].hexbin(x_data, y_data, gridsize=50, cmap='inferno')
axs[0].axis([0, 1000, 0, 1000])
axs[0].set_title("Distributed Permutation")
cb = fig.colorbar(hb, ax=axs[0])
cb.set_label('frequency')

x_data = []
y_data = []
# start simultion for biased permutations
for simulation in range(n):
    # perfectly sorted array
    arr = [x + 1 for x in range(n)]
    for i in range(n):
        r = randint(0,n-1) # wrong way

        # swap two elements
        arr[r], arr[i] = arr[i], arr[r]

    # collect result
    for i in range(n):
        x_data.append(arr[i])
        y_data.append(i+1)
# end simulation

# plot
fig.subplots_adjust(hspace=0.5, left=0.07, right=0.93)
hb = axs[1].hexbin(x_data, y_data, gridsize=50, cmap='inferno')
axs[1].axis([0, 1000, 0, 1000])
axs[1].set_title("Biased Permutation")
cb = fig.colorbar(hb, ax=axs[1])
cb.set_label('frequency')

plt.show()

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。