之前写随机的时候,不管是在打OI的那段时间还是在写游戏的那段时间,用的随机选择(不允许重复)算法都是很笨的。这里总结一下我用过的随机选择算法并且提一下Fisher-Yates洗牌算法。

(前三种做法都是我自己用过的, 估计也不会是什么有趣有用的算法,不过这里写出来权当开拓眼界和记录思路,实在懒的写并且没有什么特别严格的要求的话这些做法也能勉强达到效果)

暴力

没啥技术含量,就是维护一个vis数组,每次rand一个1到n的数,然后判断是不是已经vis过了,据此判断下一位应该选谁。

这样的思路有很大的问题。当所需取出的元素数量m很接近总数n时,比如,m=99,n=100时,在这种情况下,越往后选rand出重复数字的概率越大,因此效率上可能不太乐观。当然如果在m和n相比很小的时候,这种算法还是可以用的。最大的好处是写起来太方便了,完全没什么思考。

排序

假如这n个数的大小范围在0~a-1,那么可以根据这样的方法生成一个随机序列:

将每个数加上rand*a,然后对数组进行排序,然后每个数再对a取模。

这个方法希望的是通过给每个数加上一个随机的权值,然后根据这样的随机来获得一个排列。这样的做法不会像上边的暴力算法一样因为重复而耗费大量时间,但是同时它也有很严重的问题。举个例子:

假如要对 0,1,2,3,40,1,2,3,40,1,2,3,4进行一次随机排列。现在对他们五个分别加上rand*5。假如现在得到了这样的数列:15,26,27,33,415,26,27,33,415,26,27,33,4,那么排序后的结果就是4,15,26,27,334,15,26,27,334,15,26,27,33,然后再把这个数列还原回去,得到的就是4,0,1,2,34,0,1,2,34,0,1,2,3。

这里我们只对其中两个数的顺序提出质疑:既然1和2都是加上了3*5,凭什么就要把1排到2前边啊?

这就是这种算法的问题所在。虽然实际操作时rand的范围可能比较大,但是也无法保证两个数随机到的权值一定是不同的。而一旦两个数的权值相同,就会导致原本在前面的数还在前面。这就不太符合期望得到的随机性,至少感觉上来说是这样。

当然如果真的想用这种方法,我觉得也可以再赋一个权值,总之就是尽量消除上边提到的那种偶然现象呗。

全排列

之前还考虑过一种方法,就是dfs求一下全排列。通过rand来确定要取哪个排列。

比如我要对0,1,2,3,40,1,2,3,40,1,2,3,4求一个排列,那么我就先rand取一个数,而这个数应当小于5个数的全排列数目,即120。比如这个随机到的数是3,那么就表示要取第3个得到的排列,即0,1,3,2,40,1,3,2,40,1,3,2,4。

不过求全排列的复杂度实在是太高,n稍微大一点就没法玩了。而且这种方法会得到很多冗余的信息,比如没有取到的排列,我们耗费时间求出来,但是实际上和我们的需求几乎没关系。

不过快速求指定位置排列的算法好像也有,所以应该还是有优化空间的。

Fisher-Yates

Fisher-Yates得到的排列就很靠谱了。

它的流程是这样的:从数组的开头开始一位一位往后移,在到达第i位时,随机一个i到n-1的数字k,交换a[i]和a[k]。

由上边的流程可以看出,每经过一位之后,交换到这一位的数字就不会再被用到,也就是会确定a[i]的值。而每一次进行交换实际上就是在从剩下的数里选一个加入已选择的序列。

OK,结束。

随机排列算法(Fisher-Yates)相关推荐

  1. leetcode 519. Random Flip Matrix | 519. 随机翻转矩阵(洗牌算法Fisher–Yates shuffle)

    题目 https://leetcode.com/problems/random-flip-matrix/ 题解 看了答案: 洗牌算法 Fisher–Yates shuffle Fisher–Yates ...

  2. Fisher–Yates shuffle 算法

    简单来说 Fisher–Yates shuffle 算法是一个用来将一个有限集合生成一个随机排列的算法(数组随机排序).这个算法生成的随机排列是等概率的.同时这个算法非常高效. Fisher–Yate ...

  3. 费雪耶兹(Fisher–Yates) 也被称作高纳德( Knuth)随机置乱算法

    Fisher–Yates随机置乱算法也被称做高纳德置乱算法,通俗说就是生成一个有限集合的随机排列.Fisher-Yates随机置乱算法是无偏的,所以每个排列都是等可能的,当前使用的Fisher-Yat ...

  4. 洗牌算法(Fisher–Yates Shuffle and Knuth-Durstenfeld Shuffle)

    一.Fisher–Yates Shuffle 1.算法思想: 从原始数组中随机抽取一个新的数字到新数组. 2.算法描述: 初始化原始数组和新数组,原始数组长度为n(已知): 针对未处理的原始数组元素( ...

  5. js打乱数组内元素顺序(Fisher–Yates shuffle洗牌算法)

    如何将数组内元素顺序打乱呢?这里小shy向大家介绍一种算法. Fisher–Yates shuffle:洗牌算法. 通俗理解: 先将数组最后一位元素作为参考点,将这个参考点和数组其他位置的元素(使用随 ...

  6. JS 数组打乱 Fisher–Yates shuffle(费舍尔-耶茨 洗牌)

    原理 : Fisher–Yates shuffle 洗牌算法是什么,为什么满足需求? 这里,我们简单借助图形来理解,非常简单直观.你接下来就会明白为什么这是理论上的完全乱序(图片来源于网络). 首先我 ...

  7. 洗牌算法(Fisher–Yates高纳德置乱算法)

    2019独角兽企业重金招聘Python工程师标准>>> function getRandomInt(min, max) {return Math.floor(Math.random( ...

  8. 数组洗牌 Fisher Yates

    看播放器代码时发现的这个洗牌算法,再网上查了一番 作用是把数组变成随机序列,原理类似于从牌堆A中随机抽牌放进牌堆B 代码1:  返回一个由(数组下标)组成的数组 function random(len ...

  9. 有哪些令人拍案叫绝的算法?

    介绍一个简单易懂然后又让你拍案叫绝的算法! 这个算法的代码量很少,却很惊艳. 它就是传说中的 洗牌算法 ! 小技巧:看到一个好答案,想点赞又嫌麻烦,可以双击屏幕自动点,既能鼓舞作者,又能很方便自己下次 ...

  10. 扫雷与算法:如何随机化的布雷(二)之洗牌算法

    前言:扫雷与算法:如何随机化的布雷(一) 先来思考一个问题:有一个大小为 100 的数组,里面的元素是从 1 到 100 按顺序排列,怎样随机的从里面选择 1 个数? 最简单的方法是利用系统的方法 M ...

最新文章

  1. java在线书城系统_二手书城系统 本设计为基于JAVA的网上书店系统 - 下载 - 搜珍网...
  2. 2018.10.25-dtoj-2903-蛋糕(cake)
  3. 玲珑杯 ACM Round #10
  4. 全球变暖java_第九届 蓝桥杯 JavaB组 全球变暖
  5. pascal行人voc_利用Pascal VOC目标检测数据深度学习进行目标检测
  6. Java:Lombok插件用法笔记
  7. 使用nginx分片功能提升缓存效率,支持可拖拽式播放视频
  8. 高中计算机教师考试专业知识,高中教师资格证计算机专业考试内容
  9. Python-进阶-装饰器小结
  10. matlab 画x a的直线方程式,matlab画如x=a和y=b这种水平线和垂线的命令是什么,谢谢...
  11. linux vm编辑文件命令行,linux vm编辑器操作
  12. 微信小程序html的font-size,字体大小(font-size)
  13. ILOG Gantt 3.0 注册机
  14. 二分查找及查找左、右边界
  15. 左手Python2 右手Python3,我该选择谁?
  16. uniapp写小程序组件封装修改数据不渲染
  17. 微信公众号-上传永久素材-中文文件名乱码 问题记录
  18. 用计算机处理信息的过程,计算机处理信息的全过程
  19. Android位置模拟并实现 —— 逆向钉钉打卡Xposed Plugin
  20. 2019年4月份整理的Unity3D 20个实用插件-免费下载

热门文章

  1. Win10系统,ColorPix取色位置偏移如何解决?
  2. 用usbserver实现加密狗共享
  3. 15个超级实用web开发实用工具
  4. 模块化编程(C语言)
  5. QThread如何优雅实现暂停(挂起)功能
  6. msfconsole漏洞扫描工具详解
  7. Unity安卓端重启游戏
  8. 付费音乐如何下载???
  9. python自动生成字幕脚本_自动生成字幕软件?
  10. 硬盘保护系统破解器下载、crdisk硬盘保护克星下载