这里记录了一些有趣的算法,http://www.keithschwarz.com/interesting/,里边就包括洗牌算法 Fisher-Yates Shuffle。
算法目的,是在一个数组中,将所有元素等概率随机打乱,就像完美的洗牌一样。
算法流程就是,在长度为 n 的数组 arr 中,第一次在 [ 0, n-1 ] 中随机出一个位置 i,将 arr[i] 和 arr[0] 交换,第二次,在 [ 1, n-1 ] 中随机出一个位置 i,将 arr[i] 和 arr[1] 交换,以此类推,执行 n - 1 次。
数学证明:
1、每个数随机到位置 0 的概率很明显是
1
n
\frac {1}{n}
n1
2、每个数随机到位置 1 的概率是
n
−
1
n
∗
1
n
−
1
=
1
n
\frac {n - 1}{n}\ast\frac {1}{n - 1} = \frac {1}{n}
nn−1∗n−11=n1
3、以此类推,每个数随机到每个位置的概率都是
1
n
\frac {1}{n}
n1
代码如下:
/**************************************************************************
* File: RandomShuffle.hh
* Author: Keith Schwarz (htiek@cs.stanford.edu)
*
* An implemention of a function for randomly permuting the elements of a
* sorted range. The algorithm is an implementation of the Fisher-Yates
* shuffle (also called the Knuth shuffle), which works by randomly selecting
* an element from the the array and swapping it to the front, then recursively
* repeating the process on the rest of the array. It runs in linear time
* and with only constant space.
*
* This implementation, by default, works using the system rand function,
* which is not ideal if cryptographic randomness is desired. Consequently,
* like the STL algorithm random_shuffle, the algorithm allows for a custom
* random generator to be passed into the function.
*/
#ifndef RandomShuffle_Included
#define RandomShuffle_Included
#include <algorithm> // For iter_swap
#include <cstdlib> // For rand
/**
* Randomly permutes the elements in the range [begin, end), using the system
* rand function as a source of randomness.
*/
template <typename RandomIterator>
void RandomShuffle(RandomIterator begin, RandomIterator end);
/**
* Randomly permutes the elements in the range [begin, end),
* using the provided callback as a source of randomness.
* The generator should be callable as a nullary function which produces a uniformly-distributed
* random value over a range at least as large as the input range.
*/
template <typename RandomIterator, typename RandomGenerator>
void RandomShuffle(RandomIterator begin, RandomIterator end, RandomGenerator rnd);
/* Main implementation of the algorithm. */
template <typename RandomIterator, typename RandomGenerator>
void RandomShuffle(RandomIterator begin, RandomIterator end, RandomGenerator rnd) {
for (RandomIterator itr = begin; itr != end; ++itr)
std::iter_swap(itr, itr + rnd() % (end - itr));
}
/* Default implementation just uses rand. */
template <typename RandomIterator>
void RandomShuffle(RandomIterator begin, RandomIterator end) {
RandomShuffle(begin, end, std::rand);
}
#endif
LeetCode - 384. Shuffle an Array
这道题就是实现洗牌算法,代码如下:
class Solution {
public:
vector<int> origin, cur;
Solution(vector<int>& nums) : origin(nums), cur(nums) {
}
/** Resets the array to its original configuration and return it. */
vector<int> reset() {
return origin;
}
/** Returns a random shuffling of the array. */
vector<int> shuffle() {
const int len = cur.size();
for(auto ite = cur.begin(); ite != cur.end(); ++ite)
swap(*ite, *(ite + rand() % (cur.end() - ite)));
return cur;
}
};