shuffle洗牌算法java_洗牌算法shuffle[通俗易懂]

洗牌算法1.背景阿里的面试的时候做的一道笔试题:题目:写一个方法,入参为自然数n(n>0),返回一个自然数数组,数组长度为n,元素为[1,n]之间,且每个元素不重复,数组中各元素顺序要求随机;实例1:输入:N=3输出:132实例2:输入:N=5输出:32514当时我的解法(写了两种方法):写的好烂,面完和面试官交流的时候面试官让我看下Collect…

大家好,又见面了,我是你们的朋友全栈君。

5f86bc314e29

洗牌算法

1.   背景

阿里的面试的时候做的一道笔试题:题目:写一个方法,入参为自然数n  (n > 0),返回一个自然数数组,数组长度为n,元素为[1,n]之间,且每个元素不重复,数组中各元素顺序要求随机;

实例1: 输入: N = 3  输出: 132

实例2: 输入: N = 5   输出: 32514

当时我的解法(写了两种方法):

5f86bc314e29

5f86bc314e29

写的好烂,面完和面试官交流的时候面试官让我看下Collections.shuffle的源码,于是乎就开始研究这个“洗牌算法”。

2.洗牌算法

洗牌就是将原有的排序打乱的一个过程,我们可以通过抽牌、换牌和插牌三种方式进行洗牌。最常用的洗牌算法:即Fisher-Yates Shuffle和Knuth-Durstenfeld Shhuffle,我们分别学习一下两种洗牌算法。

2.1 Fisher-Yates Shuffle

所述费舍尔-耶茨洗牌是一种算法:用于产生随机排列的有限的序列,简单地说,该算法对序列进行洗牌。

算法的自然语言描述为(给定1到N的序列):①记下从1到N的数字。

②从1到结尾的未删除数字(包括)之间选择一个随机数k。

③从低端开始计数,剔除尚未剔除的第k个数字,并将其写下一个单独的列表的末尾。

④从第2步开始重复,直到所有数字都被删除。

⑤现在在步骤3中写下的数字序列就是原始序列的随机排列。

理论上的费舍尔-耶茨洗牌算法的时间复杂度为O(n²),空间复杂度O(n)。

2.2 Knuth-Durstenfeld Shuffle

所述克努斯-杜斯腾菲尔德算法是一个现代版的费舍尔-耶茨算法,我们实现Fisher和Yates算法时会花费不必要的时间来用来计算上面第3步中的剩余数字,但Durstenfeld的解决方案是将“删除”的数字移到列表的末尾,然后将每个被删除的数字交换为最后一个未删除的数字迭代,简言之:每次迭代时交换这个被取出的数字到原始列表的最后。这将算法的时间复杂度从O(n²)降低到了O(n)。

伪代码实现://To shuffle an arrayaofnelements  (indices  0…n-1):

forifromn−1down to1do

j← random integer such that 0 ≤j≤iexchangea[j] anda[i]

按照上述的伪代码的描述,我们使用JS实现这段伪代码:

5f86bc314e29

使用ES6实现的

Knuth-Durstenfeld Shuffle

算法需要的时间正比于要随机置乱的数,不需要额为的存储空间开销,时间复杂度为O(n),空间复杂度O(1)。

3.

Collections.shuffle()

源码解析:

5f86bc314e29

shuffle方法的入口

传入待洗牌的List集合,定义一个随机数种子。

5f86bc314e29

shuffle的具体实现

获取集合的长度,其中SHUFFLE_THRESHOLD = 5,当list的长度<5或者list实现了RandomAccess接口的时候,通过倒序的循环交换索引位置与随机生成的[0,i)的索引位置。

当集合长度>5的时候,将集合转为数组,然后再次进行随机值交换,然后将数组重新set到集合里面去,这样做避免了将“顺序访问”列表洗牌到适当的位置而导致的二次行为。

主意事项:

1)用List list=ArrayList(Arrays.asList(ia)),用shuffle()打乱不会改变底层数组的顺序。

2)用List list=Arrays.aslist(ia),然后用shuffle()打乱会改变底层数组的顺序。

可以使用洗牌算法实现扫雷。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/126128.html原文链接:https://javaforall.net

(0)
上一篇 2022年4月7日 上午11:00
下一篇 2022年4月7日 上午11:20


相关推荐

  • 如何用 fiddler 捕获 https 请求

    如何用 fiddler 捕获 https 请求

    2021年9月11日
    58
  • GIMP 教程

    GIMP 教程二个内容一样,下面的新点。都是本人原创。http://linux-wiki.cn/work/gimp/index.htmhttp://www.rzgimp.com/

    2022年6月16日
    30
  • 论dts中的of_platform_populate如何选择性加载device node为platform device

    论dts中的of_platform_populate如何选择性加载device node为platform device论dts中的of_platform_populate如何选择性加载devicenode为platformdevice2016-01-2114:26909人阅读评论(0)收藏举报本文章已收录于:分类:android源码(66)作者同类文章Xlinux(60)作者同类文章X

    2022年7月24日
    13
  • 浅解一下BS和CS的区别

    浅解一下BS和CS的区别提示 文章写完后 目录可以自动生成 如何生成可参考右边的帮助文档文章目录前言一 CS 二 BS 总结前言本文章记录 BS 和 CS 的区别和优缺点一 CSCS 客户端服务器架构模式优点 充分利用客户端机器的资源 减轻服务器的负荷 一部分安全要求不高的计算任务存储任务放在客户端执行 不需要把所有的计算和存储都在服务器端执行 从而能够减轻服务器的压力 也能够减轻网络负荷 缺点 需要安装 升级维护成本较高例如 就像平时玩游戏 假如它不是 CS 模式是 BS 模式 通过网页的方式展示的 如果你的网络有些卡 你正

    2026年3月18日
    1
  • navcat15的永久激活码【在线注册码/序列号/破解码】

    navcat15的永久激活码【在线注册码/序列号/破解码】,https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月18日
    76
  • java 查看线程死锁_java 查看线程死锁

    java 查看线程死锁_java 查看线程死锁那我们怎么确定一定是死锁呢?有两种方法。1>使用JDK给我们的的工具JConsole,可以通过打开cmd然后输入jconsole打开。1)连接到需要查看的进程。2)打开线程选项卡,然后点击左下角的“检测死锁”3)jconsole就会给我们检测出该线程中造成死锁的线程,点击选中即可查看详情:从上图中我们可以看出:①在线程Thread-1中,从状态可以看出,它想申请Paper这个资源,但是这个资…

    2022年7月13日
    29

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号