洗牌演算法的奇妙技巧之絕對公平的演算法

2021-10-03 16:03:20 字數 1591 閱讀 3979

撲克牌大家都玩過吧?有沒有想過三人鬥地主是怎麼發牌的呢?

一言以蔽之,洗牌演算法要求我們設計乙個公平的演算法去完成洗牌。

洗牌?那就隨機交換其中的兩個數k次吧。

k取多少呢?對於n = 100,k取10000次太多;對於n = 1e10,k取10000次又太少,似乎不好界定。

好,就算你想方設法確定了乙個合理的k,那麼,這樣洗牌真的公平嗎?

能否保證每個位置上出現的牌都是等概率的呢?emmmm…陷入沉思。

機智的你,靈光一閃!

對於n張牌,共有n!種排列組合的情況,我們從n!種隨機選取一種,那麼每個組合出現的概率即為1/ n!,決定的公平!

yes but not best,o(n!)的時間複雜度實在是太**了,無法容忍。

啊,投降。

先上**:

import random

defrandom_shuffle

(nums)

:len

(nums)

= n for i in

range

(n -1,

-1,-

1): swap(nums[i]

, nums[random.randint(

0, i)])

defswap

(nums, i, j)

: nums[i]

, nums[j]

= nums[j]

, nums[i]

翻譯**話:

對於乙個長為n的一堆數,第一次從0 ~ n - 1中隨機選乙個整數k1,交換下標為n - 1 和 k1的元素;

第二次從0 ~ n - 2中隨機選乙個整數k2,交換下標為n - 2 和 k2的元素…以此類推,直至遍歷完成。

現在到了見證奇蹟的舉例環節

現在我們有乙個陣列nums = [1, 3, 2, 4],可以看成是4張牌,我們開始洗牌!

第一次,從前4個中隨機選乙個幸運兒,比如2,我們交換2和4,現在nums = [1, 3, 4, 2],

第一輪的概率p1即選中2的概率,p1 = 1/4

第二次,從前3個中隨機選乙個幸運兒,比如4,我們交換4和4,實際上沒變,nums = [1, 3, 4, 2],

第二輪的概率p2即4在上一輪沒被選中的概率 * 4在這一輪被選中的概率,p2 = 3/4 * 1/3 = 1/4

第三次,從前2個中隨機選乙個幸運兒,比如1,我們交換1和3,nums = [3, 1, 4, 2],

第三輪的概率p3即1在上兩輪都沒被選中的概率 * 1在這一輪被選中的概率,p3 = 3/4 * 2/3 * 1/2 = 1/4

第四輪,從前面1個數中選,額,沒得選了,就是你了,3,nums = [3, 1, 4, 2],

最後一輪的概率p4即3在上三輪都沒被選中的概率,p3 = 3/4 * 2/3 * 1/2 = 1/4

看完後,有沒有像我當時一樣發出一聲「臥槽」呢?!

ps,如果你感興趣,去看一下它的作者knuth的生平,就不覺得這麼驚訝了。

洗牌演算法的研究

在紙牌遊戲中,有個發牌過程,發牌就是把紙牌序列打亂發給遊戲者。要保證發牌是隨機的,這也符合現實中玩牌的過程,洗牌 洗牌 即產生指定資料的隨機序列,將牌序打亂。方法一 思路 將n個數依次放到隨機的位置。關鍵是每次找乙個隨機的位置。1 設定目標陣列為空 置0 1 每次產生乙個0 n 1的隨機數,看這個位...

演算法 打亂有序的演算法 洗牌演算法

本篇博文,旨在介紹洗牌演算法 並用c 實現了洗牌演算法 我們都多多少少學過幾種排序,常見的幾種排序大類有插入排序,希爾排序,選擇排序,交換排序 然而,洗牌演算法的目的是將有序的陣列進行打亂 1 利用乙個佇列 2 每次從陣列中,隨機找到乙個數 若該數沒有被選擇過,那麼就將它放入佇列中 如果被選擇過,就...

C 洗牌演算法的實現

大家在玩鬥地主的時候,每次都是隨機發牌,每個人拿到手的牌都是和上一次不一樣的。那麼電腦是如何做到隨機的呢?首先大家想到的就是採用系統本身的隨機演算法產生的隨機數,每次都根據產生的隨機數來獲取不同位置的。舉個簡單的例子 0 9這10個數,如何讓這10個數隨機排序呢,而且保證每次出現的概率都是一樣的?1...