1. 程式人生 > >隨機洗牌算法Knuth Shuffle和錯排公式

隨機洗牌算法Knuth Shuffle和錯排公式

定義 方法 wap style 交換 如何 -- 自己 spa

Knuth隨機洗牌算法:譬如現在有54張牌,如何洗牌才能保證隨機性。可以這麽考慮,從最末尾一張牌開始洗,對於每一張牌,編號在該牌前面的牌中任意一張選一張和當前牌進行交換,直至洗到第一張牌為止。參考代碼如下:

void knuth() {
        for (int i = 54; i > 1; i--) {
            int id = rand() % (i - 1) + 1;
            swap(a[i], a[id]);
        }
    }

由上述方法可知,每一張牌經過洗牌之後一定不會出現在原來位置,那麽一共會有多少情況呢,這其實就是錯排的定義,n個數的錯排數有如下遞推公式:

f(n)=(n-1)(f(n-1)+f(n-2))

公式的推導:首先讓我們假設已知n-1個數和n-2個數的錯排數,這時又在原來基礎上加了一個數字,那麽如果這n個數要構成錯排,新加入的數字一定不能出現在自己的位置上,所以它只能選擇其余的n-1個位置,不妨設選擇了第k個位置,那麽原本在第k個位置上的數又會跑到哪裏去呢,這裏有兩種情況,原本的第k個數跑到第n個數的位置上去了,這時這兩個數只是相互交換了位置,其余的n-2個數怎麽排列完全不受影響,故此時有f(n-2)種情況;再考慮原本第k個數不在第n個數的位置上,那麽除去第n個數,其余的n-1個數任然構成錯排,錯排數為f(n-1)。至此就可得遞推式f(n)=(n-1)(f(n-1)+f(n-2));

隨機洗牌算法Knuth Shuffle和錯排公式