前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >关于Collections.shuffle()方法源码阅读

关于Collections.shuffle()方法源码阅读

作者头像
Li_XiaoJin
发布2022-06-10 18:39:20
1900
发布2022-06-10 18:39:20
举报
文章被收录于专栏:Lixj's BlogLixj's Blog

这个方法是在看原型模式的示例代码时用到的,觉得挺有意思的,研究一下~

通过查看 JDK 文档可以看到这个方法的作用是使用(默认或指定)随机源对指定列表进行置换

这里通过代码来简单使用一下~

代码语言:javascript
复制

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.ListIterator;
import java.util.Random;
import java.util.RandomAccess;

/**
 * @author lixiaojin
 * @date 2021/11/17 20:53
 */
public class TestShuffle {

    private static Random r;
    private static final int SHUFFLE_THRESHOLD = 5;

    /**
     * 使用默认的随机源随机排列指定的列表。
     * @param list
     */
    public static void shuffle(List<?> list) {
        Random rnd = r;
        if (rnd == null) {

            r = rnd = new Random();
        }
        shuffle(list, rnd);
    }

    /**
     * 使用指定的随机源随机排列指定的列表。
     *
     * 当 List 长度小于 SHUFFLE_THRESHOLD(定义为5)或者是 RandomAccess 的实例时,直接以 List 的数据结构进行打乱,否则转为数组再打乱,最后转储回 List。
     *
     * @param list
     * @param rnd
     */
    public static void shuffle(List<?> list, Random rnd) {
        int size = list.size();
        //
        if (size < SHUFFLE_THRESHOLD || list instanceof RandomAccess) {
            for (int i = size; i > 1; i--) {
                swap(list, i - 1, rnd.nextInt(i));
            }
        } else {
            Object arr[] = list.toArray();

            // Shuffle array
            for (int i = size; i > 1; i--) {
                swap(arr, i - 1, rnd.nextInt(i));
            }

            // Dump array back into list
            // instead of using a raw type here, it's possible to capture
            // the wildcard but it will require a call to a supplementary
            // private method
            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) {
        // instead of using a raw type here, it's possible to capture
        // the wildcard but it will require a call to a supplementary
        // private method
        final List l = list;
        l.set(i, l.set(j, l.get(i)));
    }

    /**
     * 交换指定数组中的两个指定元素
     */
    private static void swap(Object[] arr, int i, int j) {
        Object tmp = arr[i];
        arr[i] = arr[j];
        arr[j] = tmp;
    }


    /**
     * 在第一种情况中,Arrays.asList()的输出被传递给了ArrayList()的构造器,这将创建一个引用ia的元素的ArrayList,因此打乱这些引用不会修改该数组。
     *
     * 但是,如果直接使用Arrays.asList(ia)的结果, 这种打乱就会修改ia的顺序。
     *
     * 意识到Arrays.asList()产生的List对象会使用底层数组作为其物理实现是很重要的。
     *
     * 只要你执行的操作 会修改这个List,并且你不想原来的数组被修改,那么你就应该在另一个容器中创建一个副本。
     * @param args
     */
    public static void main(String[] args) {
        Random rand = new Random(47);
        Integer[] ia = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
        System.out.println("array: " + Arrays.toString(ia));
        System.out.println("-------------------------------");
        List<Integer> list = new ArrayList<Integer>(Arrays.asList(ia));
        System.out.println("Before shufflig: " + list);
        shuffle(list, rand);
        System.out.println("After shuffling: " + list);
        System.out.println("-------------------------------");
        List<Integer> list1 = Arrays.asList(ia);
        System.out.println("Before shuffling: " + list1);
        shuffle(list1, rand);
        System.out.println("After shuffling: " + list1);
        System.out.println("-------------------------------");
        System.out.println("array: " + Arrays.toString(ia));

    }
}

当 List 长度小于 SHUFFLE_THRESHOLD(定义为5)或者是 RandomAccess 的实例时,直接以 List 的数据结构进行打乱,否则转为数组再打乱,最后转储回 List。

这里扩展一下,我们可以用这个方法实现一个洗牌功能,具体代码如下:

代码语言:javascript
复制
/**
 * 洗牌
 * @author lixiaojin
 * @date 2021/11/17 21:20
 */
public class Shuffle {
    public static void main(String[] args) {
        List<Integer> list = new ArrayList<>();
        // 将52个数字放入一个List中
        for(int i=0; i<52; i++){
            list.add(i);
        }
        // 随机打乱list数据
        Collections.shuffle(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');
            }
        }
    }
}

Copyright: 采用 知识共享署名4.0 国际许可协议进行许可 Links: https://lixj.fun/archives/关于collections-shuffle方法源码阅读

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2021-11-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
相关产品与服务
容器服务
腾讯云容器服务(Tencent Kubernetes Engine, TKE)基于原生 kubernetes 提供以容器为核心的、高度可扩展的高性能容器管理服务,覆盖 Serverless、边缘计算、分布式云等多种业务部署场景,业内首创单个集群兼容多种计算节点的容器资源管理模式。同时产品作为云原生 Finops 领先布道者,主导开源项目Crane,全面助力客户实现资源优化、成本控制。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档