java实现洗牌算法——详解Collections.shuffle()

2023-11-13

洗牌题目描述

请撰写一个简单的洗牌程序,显示洗牌结果如下:

题目分析:相当于实现52个数字随机打乱顺序(没有王)。

代码实现

@SpringBootApplication
public class HelloWorldMainApplication {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        //将52个数字放入一个List中
        for(int i=0;i<52;i++){
            list.add(i);
        }
        Collections.shuffle(list); //随机打乱list数据

        //按要求输出
        String[] flowers = {"桃", "砖", "梅", "心"};
        String[] numbers = {"A","2","3","4","5","6","7","8","9","10","J","Q","K"};
        for(int i=0;i<52;i++){
            System.out.print(flowers[list.get(i)%4] + numbers[list.get(i)/4] + " ");
            if(i%13==12){
                System.out.print('\n');
            }
        }
    }
}

其实洗牌的功能,主要依靠封装在Collection类中的shuffle()函数来对List对象打乱顺序,在下面我们会对这个函数进行详解。结果如下:

Collection.shuffle()

主要思想如下图,总元素n个,按照从后往前的每个元素i进行操作。

  • 从包括元素i之前的所有元素随机取一个元素j(有可能i==j,如图所示的最后一步操作,毕竟也要允许有洗牌之后顺序不变的情况)
  • 两个元素互相交换
  • 直到洗牌完毕,需要n-1步操作。

我们看一下代码,代码解释在注释里,swap方法里为什么新建了一个局部变量放列表对象的引用?主要是为了规避泛型的缺点,详细在另一篇博客里,传送门。大致内容是这样的,final不final不重要,主要是为了建立一个局部变量,如果不使用局部变量,而直接使用形参list,会报错。如果直接使用泛型,在调用函数的时候也会报错。这是最佳的解决方法。如果有人这里不懂,可以评论,我可以再写个博客解释。

    public static void shuffle(List<?> list) {
        Random rnd = r;
        if (rnd == null)
            r = rnd = new Random(); // 用于取随机数
        shuffle(list, rnd);
    }

   public static void shuffle(List<?> list, Random rnd) {
        int size = list.size();
    
        /**
         * 如果不是实现RandomAccess的类的对象,如链表LinkedList,直接get和set值时时间消耗大
         * 这里选择将list的值放到一个Object数组里,但这样空间消耗大,在某些比较短的list里
         * 通过阈值SHUFFLE_THRESHOLD控制时间消耗和空间消耗的平衡
         */
        if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
            for (int i=size; i>1; i--)
                //rnd.nextInt(i)可以随机取到[0,i-1]间的某一个数
                swap(list, i-1, rnd.nextInt(i));
        } else {
            Object arr[] = list.toArray();

            // 对arr进行洗牌
            for (int i=size; i>1; i--)
                swap(arr, i-1, rnd.nextInt(i));

            ListIterator it = list.listIterator();
            for (int i=0; i<arr.length; i++) {
                it.next();
                it.set(arr[i]);
            }
        }
    }

    public static void swap(List<?> list, int i, int j) {
        // 注意,这里使用中间变量l,来规避泛型通配符的缺点
        final List l = list;
        l.set(i, l.set(j, l.get(i)));
    }

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

java实现洗牌算法——详解Collections.shuffle() 的相关文章

随机推荐

  • Flink CDC问题

    这里会列举出一些关键配置和遇到的问题 一直补充 Oracle CDC 1 SUPPLEMENTAL LOG在库和表上都需要执行 不是只有表上 ALTER TABLE inventory customers ADD SUPPLEMENTAL
  • 原生js触底加载案例

    data return RoomData isBool false limit 0 isLoading false methods roomClick value location href value RoomApi this limit
  • 4.网络配置与系统管理

    个人简介 作者简介 大家好 我是W chuanqi 一个编程爱好者 个人主页 W chuanqi 支持我 点赞 收藏 留言 愿你我共勉 若身在泥潭 心也在泥潭 则满眼望去均是泥潭 若身在泥潭 而心系鲲鹏 则能见九万里天地 文章目录 网络配置
  • mysql创建表时表明加单引号_python在MySQL表名周围插入单引号(‘)

    我有一个名为project1的数据库 其中包含以下表格 systbl1 systbl2 systbl3 dataset1 dataset2 dataset3 每当添加一个新用户时 都需要授予MySQL用户odbc对dataset 表的SEL
  • 组态王串口服务器虚拟串口,串口服务器USR-N510连接组态王设置步骤

    调试目的 USB RS232或者USB RS485串口线接USR N510串口和电脑USB口 MODBUS SLAVE软件打开COM口 模拟客户串口MODBUS RTU设备 USR N510网线和电脑直连 IP设置同网段 在电脑安装USR
  • unicode编码、字符的转换和得到汉字的区位码

    一 unicode编码 字符的转换截图 二 unicode编码 字符的转换代码 using System using System Collections Generic using System ComponentModel using
  • Visual Studio MFC编程 程序调试时所遇到的问题及解决方法

    本文中记录了笔者在基于Visual Studio MFC编程时 程序调试过程中所遇到的问题及解决方法 目录 1 Visual Studio MFC中的快捷方式 1 1 问题 Visual Studio MFC中修改好程序之后 怎样编译并建立
  • QT实现串口打开和关闭

    一 查找串口 windows 下面这个循环语句用来查找可以用的串口端口 不确定有多少串口可用 也就不知道循环多少次 所以用foreach 不知道用的就百度 foreach const QSerialPortInfo info QSerial
  • Linux常用操作命令

    Shell命令基础 root localhost root 用户名账号 计算机名 用户当前工作目录 文件与目录相关命令 1 ls命令 列出目录内容 执行ls指令可列出目录的内容 包括文件目录以及子目录 ls 参数 文件或目录 若无选定目录
  • 抽象类案例

    卡类 package Java project 1 public abstract class Card private String userName private double money public abstract void p
  • 数据库的连接串(中文)

    在数据库的各种应用程序开发中 连接数据库是数据库应用程序开发的第一步 同时也是最重要的一步 而对于不同的数据库他们的连接模式各有不同 对应的连接串也不同 Sql Server ODBC o 标准连接 Standard Security Dr
  • CSS之background-position属性

    1 作用 background position是用来控制元素背景图片的位置 以图片的左上角顶点为原点 属性值为正就代表图片下移或右移 属性值为负就代表图片上移或左移 它接受三种值 关键词 比如top right bottom left和c
  • WordPress:实现发布文章自动添加TAG标签

    在给我们的WordPress博客更新文章时 大多数人应该会给文章添加一些TAG标签 文章添加TAG标签也是我们做WordPress优化必不可少的一项 但是如果每一篇文章的关键字标签都要手动添加链接 那也太麻烦了 今天给大家分享一篇自动给文章
  • java---多重循环练习

    java 多重循环练习 1 关于多重循环的嵌套使用 举例 一 循环嵌套的用法 1 更加方便 重复率低的实现多步操作 二 使用步骤 1 多个循环结构嵌套 代码如下 示例 for 变量初始值 循环条件 迭代 for 变量初始值 循环条件 迭代
  • RabbitMQ 中arguments详解(系列一之Message TTL)

    注 以下程序使用C 实现 在我们使用RabbitMQ声明队列时 其中最后一个参数是arguments 那么arguments到底有什么用呢 下面我们解释其中参数的第一中用法 即 消息过期时间 Message TTL 我们将最后一个参数arg
  • OW-DETR

    欢迎关注我的公众号 极智视界 获取我的更多笔记分享 大家好 我是极智视界 本文解读一下 基于 Transformer 的开放世界目标检测器 OW DETR 开放世界目标检测 OWOD 是一个具有挑战性的计算机视觉问题 其任务是检测一组已知的
  • 现代密码学第三次实验:不对称加密算法RSA

    现代密码学第三次实验 不对称加密算法RSA 前言 一 实验目的 二 实验环境 三 实验步骤 四 实验基本方法 五 实验程序清单 七 实验结果 八 实验总结 前言 为了帮助同学们完成痛苦的实验课程设计 本作者将其作出的实验结果及代码贴至CSD
  • python实验数据预处理案例_Python数据分析小案例——红楼梦文本分析(一) 文本预处理...

    本文开始介绍一个简单的数据分析案例 分析红楼梦文本 本文主要内容是将红楼梦文本按照章节获取每一回的标题 字数 段落数并保存到csv中方便后续数据分析 红楼梦小说文本可以在这里下载 链接 https pan baidu com s 1WEmu
  • 获取中文、英文、数字的首字母

    function getFirstChar s 获取第一个 s0 mb substr s 0 1 utf 8 一些汉字可能获取不到 可以如下单独处理 if s0 奧 return A if s0 斐 return F if s0 麒 ret
  • java实现洗牌算法——详解Collections.shuffle()

    洗牌题目描述 请撰写一个简单的洗牌程序 显示洗牌结果如下 题目分析 相当于实现52个数字随机打乱顺序 没有王 代码实现 SpringBootApplication public class HelloWorldMainApplication