洗牌算法

1. 編寫一個方法,洗一副牌。要求作到完美洗牌,換言之,這副牌52!中排列組合出現的機率相同。假設給定一個完美的隨機數發生器。html

  假設有個方法shuffle對n-1個元素有效,咱們能夠用它來打亂n個元素的次序。咱們會先打亂前n-1個元素的次序,而後,取第n個元素,將它與數組中的元素隨機交換。這是遞歸的思想。算法

  這裏咱們使用的迭代方法,咱們要作的就是遍歷整個數組,對每一個元素i,將array[i]與0和i(含)之間的隨機元素交換。數組

//隨機數產生器
int random(int lower, int higher)
{
    return lower + (rand() % (higher - lower + 1));
}
//遞歸
void shuffleArrayRecursively(int cards[], int i)
{
    if(i == 0)
        return;
    shuffleArrayRecursively(cards, i - 1);   //打亂先前部分的次數
    int k = random(0, i);   //隨機挑選索引進行交換
    swap(cards[k], cards[i]);
}
//迭代
void shuffleArrayInteratively(int cards[], int n)
{
    for(int i = 0; i < n; i++)
    {
        int k = random(0, i);
        swap(cards[k],cards[i]);
    }
}

2. 編寫一個方法,從大小爲n的數組中隨機選出m個整數。要求每一個元素被選中的機率相同。dom

  關於這個問題的證實解釋能夠參見機率問題spa

  這種問題和隨機洗牌算法類似,因此我放在一塊兒說。咱們能夠先取出源數組中的前m個元素,而後從元素m開始,迭代訪問原數組,只要k<m,就將array[i]插入到目的數組中(隨機選出)位置k。code

//隨機數產生器
int random(int lower, int higher)
{
    return lower + (rand() % (higher - lower + 1));
}
void pickMIteratively(int original[], int data[], int n, int m)
{
    for(int i = 0; i < m; i++)
    {
        data[i] = original[i];
    }
    for(int i = m; i < n; i++)
    {
        int k = random(0, i);
        if(k < m)
            data[k] = original[i];
    }
}
相關文章
相關標籤/搜索