分享人:严泽浩
目录
1.背景介绍
2.知识剖析
3.常见问题
4.解决方案
5.编码实战
6.扩展思考
7.参考文献
8.更多讨论
从字面意义上讲,就是实现洗牌的具体方法, 洗牌的目的是什么呢?在不考虑出老千的情况下,洗过的牌要足够乱才好,牌面随机分布,越乱越好! 在科研,计算机科学等很多领域都需要运用到概率分布的随机性, 所以说洗牌算法本质上是把一个给定元素集合打乱成为一个无序元素集合
简单来说 Fisher–Yates shuffle 算法是一个用来将一个有限集合生成一个随机排列的算法(数组随机排序)。 这个算法生成的随机排列是等概率的,同时这个算法非常高效。 这是一个正确且高效的算法,在我们需要解决概率分布的随机性问题时,用这个就对了!(秒天秒地秒空气)
Fisher–Yates shuffle 的原始版本, 最初描述在 1938 年的 Ronald Fisher 和 Frank Yates 写的书中, 他们使用纸和笔去描述了这个算法,并使用了一个随机数表来提供随机数。 它给出了 1 到 N 的数字的的随机排列,具体步骤如下:
注意:已经证明如果第 2 步取出的数字是真随机的,那么最后得到的排序一定也是。
Fisher and Yates 的原始版是由自然语言描述的,他默认了人类不会选择自己已经选过的牌,
然而计算机并没有这么聪明,计算机对于选过的牌是没有概念的,你必须告诉它如何处理这种情况,
否则它会重复选择,随着剩余元素的减少,它的效率会越来越低
到最后这种方法捞一张牌上来无疑是大海捞针
所以我们需要针对计算机做出进一步的优化
Knuth 和 Durstenfeld 在Fisher 等人的基础上对算法进行了改进, 在原始数组上对数字进行交互,减小了空间复杂度 该算法的基本思想和 Fisher 类似,每次从未处理的数据中随机取出一个数字, 然后把该数字放在数组的尾部,即数组尾部存放的是已经处理过的数字
Knuth-Durstenfeld Shuffle 是一个内部打乱的算法,算法完成后原始数据被直接打乱,
尽管这个方法可以节省空间,但在有些应用中可能需要保留原始数据,所以需要另外开辟一个数组来存储生成的新序列。
Inside-Out Algorithm 算法的基本思想是从前向后扫描数据,
把位置i的数据随机插入到第i个(包括第i个)位置中(假设为k),这个操作是在新数组中进行,
然后把原始数据中位置k的数字替换新数组位置i的数字。其实效果相当于新数组中位置k和位置i的数字进行交互。
Sandra Sattolo于1986年发布了一种非常相似的算法 当打算使用普通的Fisher-Yates shuffle时,很容易不经意间就实现了Sattolo算法
核心思想和Fisher–Yates shuffle算法完全一致, 区别在于:在原始数组上对数字进行交互,减小了空间复杂度 每次从未处理的数据中随机取出一个数字, 然后把该数字放在整个数组的尾部,即数组尾部存放的是已经处理过的数字, 具体步骤如下:
问题1:如何评判一个洗牌算法的优劣
算法复杂度是指算法在编写成可执行程序后,运行时所需要的资源,资源包括时间资源和内存资源。
伪随机数是用确定性的算法计算出来的似来自[0,1]均匀分布的随机数序列。 并不真正的随机,但具有类似于随机数的统计特征,如均匀性、独立性等。 在计算伪随机数时,若使用的初值(种子)不变,那么伪随机数的数序也不变。 伪随机数可以用计算机大量生成,在模拟研究中为了提高模拟效率,一般采用伪随机数代替真正的随机数。 模拟中使用的一般是循环周期极长并能通过随机数检验的伪随机数,以保证计算结果的随机性。
参考二:Fisher–Yates shuffle From Wikipedia
伪随机?真随机?宇宙中是否存在真正的随机?
感谢大家观看
BY : 严泽浩