(Counting & Probability) Fisher-Yates Shuffling & Implementation in Java

Motivation

  • We have n ≥ 1 n≥1 n1 distinct objects i.e. an array of length n n n with distinct objects, and we want to shuffle them using an algorithm such that every possible permutation out of a totally of n ! n! n! is equally likely.

The Algorithm

Description

  • Suppose we are given a random number generator.
  • Start from the last element of the array, generate a random integer between 0 0 0 and n − 1 n-1 n1 (all inclusive), say r 1 r_1 r1, and swap the r 1 r_1 r1th and the ( n − 1 ) (n-1) (n1)th elements.
  • Then generate a random integer between 0 0 0 and n − 2 n-2 n2, say r 2 r_2 r2, then we swap the r 2 r_2 r2th and the n − 2 n-2 n2th elements.
  • Continue this process until we get to generate a random integer between 0 0 0 and 1 1 1, say r n − 1 r_{n-1} rn1, then we swap r n − 1 r_{n-1} rn1st and 1 1 1th elements.
  • No matter what we generated in the last step, the next step only allows us to generate 0 = r n 0=r_n 0=rn as the only possible random integer, so we keep everything unchanged as we are swapping 0 0 0th element and the 0 0 0th element. Thus, this last step is never needed.
  • One shuffling is completed.

Pseudo Code

  • Assume arr is an array of length n ≥ 1 n≥1 n1. Assuming the array index starts at 0 0 0:
for i = n-1,....,1{ // the i = 0 step is not actually needed
	l = randInt 0 <= l <= i
	swap(arr[i], arr[l])
}

Proof

  • Let the index start from 1 1 1 from now on. We want to prove that for any permutation of the n n n objects in the original array, the probability of obtaining it by the algorithm is always 1 n ! \frac{1}{n!} n!1.
  • Observe a fact from the algorithm:
    • After the first step, whichever object from the original array gets fixed to the last position stay fixed forever because after the first step, the second step will only exchange two terms among the previous n − 1 n-1 n1 terms.
    • Same for the second step: after the second step, whichever object gets fixed to the next-to-the-last position gets fixed forever and so on.
  • Thus, a direct result of this observation is that once we choose some permutation of the objects of the original array, we can build this permutation by n n n consecutive steps that needs to be done in such an order that the first step is to decide which term goes to the last position, the second step is to decide which goes to the next to last position and so on, which will, in turn, allows us to use the multiplication principle.
  • Therefore, assume a 1 , . . . , a n a_1,...,a_n a1,...,an is an arbitrary permutation, with their original indices in the array being x 1 , . . . . , x n x_1,....,x_n x1,....,xn. We examine all the steps needed to obtain this permutation:
  • The first step generates a random integer between 1 1 1 and n n n, so if the generator is indeed random, the probability of generating x n x_n xn from { 1 , . . . , n } \{1,...,n\} {1,...,n} is 1 n \frac{1}{n} n1, therefore, the probability that a n a_n an gets fixed to the last position is 1 n \frac{1}{n} n1.
  • The second step generates a random integer in S = { 1 , . . . , n } ∖ { x n } S=\{1,...,n\} \setminus \{x_n\} S={1,...,n}{xn}, which are n − 1 n-1 n1 integers, so P ( { P(\{ P({generating x n − 1 ∈ S } ) = 1 n − 1 x_{n-1}\in S\})=\frac{1}{n-1} xn1S})=n11, which is the probability that a n − 1 a_{n-1} an1 gets fixed to the ( n − 1 ) (n-1) (n1)th position.
  • Similarly, the probability that a n − 2 a_{n-2} an2 gets fixed to the ( n − 2 ) (n-2) (n2)th position is thus 1 n − 2 \frac{1}{n-2} n21.
  • This process continues until we have reached the 1 1 1st position, where the only integer that can be generated is 1 1 1, and we only have one index, x 1 x_1 x1, left (as we have chosen n − 1 n-1 n1 integers already), so the probability that a 1 a_1 a1 gets fixed to the first position is certainly 1 1 1.
  • By multiplication principle, since we achieved the permutation a 1 , . . . , a n a_1,...,a_n a1,...,an by these n n n consecutive steps, the probability of getting this permutation is thus 1 n ⋅ 1 n − 1 . . . ⋅ 1 = 1 n ! \frac{1}{n}\cdot \frac{1}{n-1} ...\cdot 1=\frac{1}{n!} n1n11...1=n!1

Implementation in Java

	int n = 5;
	char[] CardValues = new char[] {'a','b','c','d','e'};
  	for(int i = n-1; i >= 0; i--){
  		int r = (int) ((i + 1) * Math.random()); // r in [0,i]
  		char temp = CardValues[i];
  		CardValues[i] = CardValues[r];
  		CardValues[r] = temp;
  	}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值