STL中的洗牌程序为random_shuffle,其源码如下:
template <class RandomAccessIterator>
inline void random_shuffle(RandomAccessIterator first, RandomAccessIterator last) {
if(first != last)
for(RandomAccessIterator i = first + 1; i != last; ++i)
iter_swap(i, first + (rand() % ((i - first) + 1)));
}
洗牌算法重要的是要保证算法符合均匀分布,即每张牌在每个位置出现的位置均等。
问题:random_shuffle算法洗出来的牌能符合均匀分布吗?
ANS:当然可以。证明如下:
假设有N张牌(假设点数为1~54,位置为1~54),采用倒推法,按算法可知,最后一个位置的牌(54)出现在其它位置上的概率均为1/54,符合原则
倒数第二个位置的牌(53),出现在其它位置的概率为1/53 - 1/53 * 1/54 = 1/54,也符合原则
扩展到任意位置的牌(n),其出现在其它位置的概率为1/n - 1/n * 1/(n+1) - 1/(n+1) * 1/(n+2) - ... - 1/53 * 1/54 = 1/54 (利用1/n - 1/n*1/(n+1) = 1/(n+1)),也符合原则
故该算法符合均匀分布原则。
C++11后STL弃用了random_shuffle,改为了随机数性能更好的函数shuffle,其中使用了正态分布来产生更接近随机的随机数,实现如下:
void shuffle (RandomAccessIterator first, RandomAccessIterator last, URNG&& g) { for (auto i=(last-first)-1; i>0; --i) { std::uniform_int_distribution<decltype(i)> d(0,i); swap (first[i], first[d(g)]); } }