【算法】洗牌算法Fisher–Yates shuffle
C#语言一般都是调用随机函数Random.Next函数,在一个范围内随机出一个数字。但是当我们需要将n个数据随机选择k个数。怎么办呢?
方案一:随机出一个数,然后从剩下的数里面接着随机。
方案二:每次都从n个数据里面随机出一个数,遇到重复的,放回去。接着随机,直到随机出k个数。
我们的目的是不管用哪个方案,我们都需要保证选出的数要是等概率的。
方案一:取第1个数是1/n,第二个数是1/(n-1)…1
方案二:最坏的情况下我们从100个里面随机出99个,越到后面随机出来的重复率越高。
Fisher–Yates shuffle
Fisher–Yates shuffle算法是高效和等概率的一个洗牌算法。其核心思想是从1到n之间随机出一个数和最后一个数(n)交换,然后从1到n-1之间随机出一个数和倒数第二个数(n-1)交换…假设我们有5个数0,1,2,3,4
0,1,2,3,4
1.从[0,4]这5个位置中(包含0和4)随机出一个数(比如是3)和4号交换。
0,1,2,4,3
第4号位置放3的概率就是1/5
2.从[0,3]这4个位置中(包含0和3)随机出一个数(比如是0)和3号交换。
4,1,2,0,3
第3号位置放0的概率就是(4/5)*(1/4)=1/5
3.从[0,2]这3个位置中(包含0和2)随机出一个数(比如是0)和2号交换。
2,1,4,0,3
第2号位置放4的概率就是(4/5)x(3/4)x(1/3)=1/5
4.从[0,1]这2个位置中(包含0和1)随机出一个数(比如是0)和1号交换。
1,2,4,0,3
第1号位置放2的概率就是(4/5)x(3/4)x(2/3)x(1/2)=1/5
5.从[0,0]这1个位置中(包含0和0)随机出一个数(比如是0)和0号交换。
1,2,4,0,3
第0号位置放1的概率就是(4/5)x(3/4)x(2/3)x(1/2)=1/5
其实第5步骤就是不用交换了。
那么我们再回到之前的问题,取出k个数。其实我们将这几个数字洗完之后,即已经随机打乱了。所以从里面按照顺序取出k个数即可。
如果本文对你有所帮助,欢迎赞赏~~~
欢迎关注微信公众号:Unity游戏开发笔记
QQ群: