c_cpp Fisher-Yates shuffle算法,随机随机播放

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c_cpp Fisher-Yates shuffle算法,随机随机播放相关的知识,希望对你有一定的参考价值。

/*
Shuffle a given array
Fisher–Yates shuffle Algorithm works in O(n) time complexity. The assumption here is, we are given a 
function rand() that generates random number in O(1) time.
The idea is to start from the last element, swap it with a randomly selected element from the whole 
array (including last). Now consider the array from 0 to n-2 (size reduced by 1), and repeat the process 
till we hit the first element.
*/


+----------------------+

http://stackoverflow.com/questions/1685339/verify-knuth-shuffle-algorithm-is-as-unbiased-as-possible
http://stackoverflow.com/questions/5027273/how-to-test-if-a-deck-of-cards-has-been-shuffled-enough-in-java
https://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
http://blog.codinghorror.com/shuffling/
http://www.geeksforgeeks.org/shuffle-a-given-array/
https://techblog.bitzino.com/2012-06-30-provably-fair-shuffling-through-cryptography.html

Fisher–Yates shuffle (Knuth shuffle)

To shuffle an array a of n elements (indices 0..n-1):
  for i from n − 1 downto 1 do
       j ← random integer such that 0 ≤ j ≤ i
       exchange a[j] and a[i]


The Fisher–Yates shuffle is unbiased, so that every permutation is equally likely. The modern version of the algorithm is also rather efficient, requiring only time proportional to the number of items being shuffled and no additional storage space. Fisher–Yates shuffling is similar to randomly picking numbered tickets (combinatorics: distinguishable objects) out of a hat without replacement until there are none left.

Advantages:
(1) asymptotic time and space complexity are optimal. O(N) time and O(1) space
(2) guaranteed to produce unbiased results
(3) can be stopped halfway through, or even stopped and restarted repeatedly, generating the permutation incrementally as needed
(4) is sequential not parallel

===============

Other algorithms to shuffle:
assigns a random number to each element of the set to be shuffled and then sorts (can use Radix sort) the set according to the assigned numbers
(1) although general sorting is O(n log n), numbers are efficiently sorted using Radix sort in O(n) time
(2) produces unbiased results
(3) has a simple parallel implementation

But,
(1) must ensure that the assigned random numbers are never duplicated
(2) requires asymptotically larger space: O(n) additional storage space for the random numbers

===============
merging two sequences by repeatedly choosing one of them with equal probability (until the choice is forced by the exhaustion of one sequence) does not produce results with a uniform distribution; instead the probability to choose a sequence should be proportional to the number of elements left in it. In fact no method that uses only two-way random events with equal probability ("coin flipping"), repeated a bounded number of times, can produce permutations of a sequence (of more than two elements) with a uniform distribution, because every execution path will have as probability a rational number with as denominator a power of 2, while the required probability 1/n! for each possible permutation is not of that form.

===============

How to verify a shuffle algorithm is unbiased?

(1) take some relatively small array size, perform a large number of shuffles on it, 
(2) count how many times you observe each permutation, and then 
(3) perform Pearson's Chi-square test to determine whether the results are uniformly distributed over the permutation space.







// imagine a deck of cards. The top one is numbered N-1. The bottom one is
// numbered 1. We randomly select one card from the deck (including the top),
// then swap with the top one, then, remove the top one.

void shuffle(vector<int> &a) {
    int N = a.size();
    for(int i=N-1; i>0; --i) {  // gist, note, i>0 not i>=0
        int r = rand() % (i+1); // gist, note, i+1 not i. "rand() % (i+1)" means 
                                // generate rand numbers from 0 to i
        swap(a[i], a[r]);
    }    
}

// the implementation in C++ STL
template <class RandomAccessIterator, class RandomNumberGenerator>
  void random_shuffle (RandomAccessIterator first, RandomAccessIterator last,
                       RandomNumberGenerator& gen)
{
  iterator_traits<RandomAccessIterator>::difference_type i, n;
  n = (last-first);
  for (i=n-1; i>0; --i) {
    swap (first[i],first[gen(i+1)]);
  }
}

以上是关于c_cpp Fisher-Yates shuffle算法,随机随机播放的主要内容,如果未能解决你的问题,请参考以下文章

javascript Fisher-Yates Shuffle洗牌算法

使用Fisher-Yates 洗牌算法实现random_shuffle函数

sql Fisher-Yates在PL / SQL中进行了随机播放

csharp Fisher-Yates来自https://stackoverflow.com/questions/273313/randomize-a-listt

关于JavaScript的数组随机排序

[spark] shuffle