记得当年搞NOIp时,我犯过一个相当严重的错误:错误地把Floyd算法的i, j, k三层循环的位置顺序搞颠倒了。直到准备省选时我才突然意识到,Floyd算法应该最先枚举用于松驰操作的那个“中间变量”k,表示只经过从1到k的顶点的最短路;而我却一直习惯性地以为i, j, k应该顺次枚举。令人惊讶的是,这个错误跟了我那么久我居然从来都没有注意到过。后来,我发现有我这种经历的人不止一个。惯性思维很可能会让你接受一些明显错误的算法,并且让你用得坦坦荡荡,一辈子也发觉不了。
假使你需要把一个数组随机打乱顺序进行重排。你需要保证重排后的结果是概率均等、完全随机的。下面两种算法哪一种是正确的?其中,random(a,b)函数用于返回一个从a到b(包括a和b)的随机整数。
1. for i:=1 to n do swap(a[i], a[random(1,n)]);
2. for i:=1 to n do swap(a[i], a[random(i,n)]);
如果不仔细思考的话,绝大多数人会认为第一个算法才是真正随机的,因为它的操作“更对称”,保证了概率均等。但静下心来仔细思考,你会发现第二种算法才是真正满足随机性的。为了证明这一点,只需要注意到算法的本质是“随机确定a[1]的值,然后递归地对后n-1位进行操作”,用数学归纳法即可轻易说明算法的正确性。而事实上,这段程序一共将会产生n*(n-1)*(n-2)*...*1种等可能的情况,它们正好与1至n的n!种排列一一对应。
有人会问,那第一种算法为什么就错了呢?看它的样子多么对称美观啊……且慢,我还没说第一种算法是错的哦!虽然第一种算法将产生比第二种算法更多的可能性,会导致一些重复的数列,但完全有可能每种数列重复了相同的次数,概率仍然是均等的。事实上,更有可能发生的是,这两种算法都是正确的,不过相比之下呢第一种算法显得更加对称美观一些。为此,我们需要说明,第一种算法产生的所有情况均等地分成了n!个等价的结果。显然,这个算法将会产生n^n种情况,而我们的排列一共有n!个,因此n^n必须能够被n!整除才行(否则就不能均等地分布了)。但是,n!里含有所有不超过n的质数,而n^n里却只有n的那几个质因子。这表明要想n^n能被n!整除,n的质因子中必须含有所有不超过n的质数。这个结论看上去相当荒唐,反例遍地都是,并且直觉上告诉我们对于所有大于2的n这都是不成立的。为了证明这一点,只需要注意到2是质数,并且根据Bertrand-Chebyshev定理,在n/2和n之间一定还有一个质数。这两个质数的乘积已经大于n了。搞了半天,第一种看似对称而美观的算法居然是错的!
参考资料:http://adrianquark.blogspot.com/2008/09/how-to-shuffle-array-correctly.html
转载自:http://www.matrix67.com/blog/archives/879
分享到:
相关推荐
1. **全随机洗牌算法**: - **最笨的洗牌算法**:遍历数组,每次随机生成一个未取过的索引,将其取出并放入新数组。这种方法时间复杂度为O(N^2),空间复杂度为O(N),因为需要额外的存储空间记录已取的元素。 - **...
判断是否是引用类型,浮点数运算(解决计算机运算浮点数精度丢失问题),数组随机洗牌算法,随机整数范围,将阿拉伯数字翻译成中文的大写数字,将数字转换为大写金额,判断一个元素是否在数组中,数组删除其中一个...
### 随机数生成与洗牌算法 #### 一、随机数生成 **定义**:随机数是指在一定范围内,各个数值出现的概率相同且无法预测的数字。 **特性**: 1. **不可预测性**:任何算法都无法事先确定生成的具体数值。 2. **...
随机洗牌算法是计算机科学中一项非常基础且有趣的算法。在编程语言如JavaScript中,随机洗牌算法的实现往往涉及到数组的随机排序。这种算法可以广泛应用于游戏、随机化测试数据、模拟等场景。 JavaScript中的随机洗...
在计算机科学领域,洗牌算法是一种常见的随机化算法,主要用于将一个序列中的元素打乱顺序,使其呈现出随机分布的状态。这种算法在多种场景下都有广泛的应用,如游戏开发、密码学、数据处理等。本文将详细解析一种...
3. **优化洗牌算法**:虽然Collections.shuffle()已经足够随机,但也可以通过自定义随机数生成器或者Fisher-Yates(Knuth)洗牌算法来进一步理解洗牌过程。 4. **优化发牌算法**:考虑特殊情况,如玩家数量变化或...
洗牌算法是编程领域中一个有趣的议题,常用于模拟各种随机事件,比如电子游戏中抽取卡片、抽奖系统等。本文将探讨三种不同的洗牌算法思路,它们各有优缺点,适用于不同的场景。 首先,我们来理解洗牌算法的核心目标...
JavaScript中实现随机打乱数组顺序的算法通常被称为数组的洗牌算法,它在数据处理、游戏开发等领域有着广泛的应用。洗牌算法的核心思想是将数组中的元素随机重新排序。为了保证随机性,一个好的洗牌算法应当保证每个...
传统的洗牌算法往往基于随机技术,存在效率低下的问题,尤其是当样本量巨大时,对系统资源的需求量会大幅增加,导致时间效率低下。为了解决这一问题,文中提出了基于折叠技术的大数据样本洗牌算法。 折叠技术是一种...
这是一种常见的洗牌算法,能够高效地对数组进行随机排序。算法的核心思想是从数组尾部开始,每次随机选择一个元素与当前位置的元素交换,从而保证每个元素被选中的概率相同。 **具体步骤:** - 初始化一个包含所有...
常见的洗牌算法有Fisher-Yates(也称为Knuth)洗牌算法,它保证了完全的随机性,并且在计算机科学中被广泛采用。 二、Fisher-Yates(Knuth)洗牌算法 1. 初始化:假设我们有一组编号为0到N-1的元素,代表一副未洗...
洗牌算法(Shuffle Algorithm)是一种常见的算法,主要用于随机地重新排列一组数据的顺序。在实际应用中,它经常被用于游戏开发、模拟实验以及各种需要随机化处理的场景。 #### 二、核心思想 洗牌算法的核心思想是...
这个函数通常采用Fisher-Yates(也称为Knuth)洗牌算法,该算法在原地修改数组,避免了额外的空间开销。算法步骤如下: - 从最后一张牌开始,即索引为`n-1`的牌,与随机位置的牌交换。 - 对倒数第二张牌做同样的...
洗牌算法,又称为随机排列生成,是编程中处理随机性问题的一个常见场景,常用于游戏中的随机事件、随机选择等。它的目标是将一个有序序列(如1到M的整数)随机重排,形成一个看似无规律的新序列。 在描述的算法中,...
这个话题涉及到使用Visual Basic(VB)编程语言来实现一个洗牌算法,这是许多卡牌游戏、随机选择等应用中的核心部分。下面我们将详细探讨这个主题。 首先,洗牌算法是编程中用于模拟洗牌过程的一种方法,确保每次...
《完美洗牌问题》 在计算机科学中,完美洗牌是指对一个序列进行操作,使得序列中的每个元素在洗牌后都有...通过学习这些论文,我们可以掌握如何设计和实现高效、公正的完美洗牌算法,从而在实际问题中得到广泛应用。
具体地,使用了经典的洗牌算法——Fisher-Yates洗牌算法的一个变体。这种算法的工作原理是从数组中随机选择一个元素,并与当前位置的元素交换,这样可以确保每张牌被选中的概率相等。 **3. 算法设计:洗牌算法** ...