Collections.shuffle()源码分析
Java.util.Collections类下有一个静态的shuffle()方法,如下:
1)static void shuffle(List<?> list) 使用默认随机源对列表进行置换,所有置换发生的可能性都是大致相等的。
2)static void shuffle(List<?> list, Random rand) 使用指定的随机源对指定列表进行置换,所有置换发生的可能性都是大致相等的,假定随机源是公平的。
源码展示:
public class Collections {
private static Random r;
private static final int SHUFFLE_THRESHOLD = 5; public static void shuffle(List<?> list) {
if (r == null) {
r = new Random();
}
shuffle(list, r);
} 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
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) {
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;
} }
基本应用(打乱一个int数组):
public class ShuffleTest {
public static void main(String[] args) {
List<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < 10; i++)
list.add(new Integer(i));
System.out.println("打乱前:");
System.out.println(list); for (int i = 0; i < 5; i++) {
System.out.println("第" + i + "次打乱:");
Collections.shuffle(list);
System.out.println(list);
}
}
}
经典应用(洗牌):
import java.util.ArrayList;
import java.util.List;
import java.util.Random; public class CollectionsShuffle {
public static void main(String[] args) {
List<Card> cards = new ArrayList<Card>();
// 生成一副牌
for (int rank = Card.THREE; rank <= Card.DEUCE; rank++) {
cards.add(new Card(Card.DIAMOND, rank));
cards.add(new Card(Card.CLUB, rank));
cards.add(new Card(Card.HEART, rank));
cards.add(new Card(Card.SPADE, rank));
}
cards.add(new Card(Card.JOKER, Card.BLACK));
cards.add(new Card(Card.JOKER, Card.COLOR));
System.out.println(cards.toString());
/*
* [方块3, 梅花3, 红桃3, 黑桃3, 方块4, 梅花4, 红桃4, 黑桃4, 方块5, 梅花5, 红桃5, 黑桃5, 方块6,
* 梅花6, 红桃6, 黑桃6, 方块7, 梅花7, 红桃7, 黑桃7, 方块8, 梅花8, 红桃8, 黑桃8, 方块9, 梅花9, 红桃9,
* 黑桃9, 方块10, 梅花10, 红桃10, 黑桃10, 方块J, 梅花J, 红桃J, 黑桃J, 方块Q, 梅花Q, 红桃Q, 黑桃Q,
* 方块K, 梅花K, 红桃K, 黑桃K, 方块A, 梅花A, 红桃A, 黑桃A, 方块2, 梅花2, 红桃2, 黑桃2, 小王, 大王]
*/
// 经典洗牌算法
Random random = new Random();
for (int i = cards.size(); i > 1; i--) {
int m = random.nextInt(i);
swap(cards, i - 1, m);
}
System.out.println(cards.toString());
/*
* [黑桃7, 黑桃A, 梅花A, 红桃9, 梅花4, 红桃K, 方块5, 梅花7, 梅花6, 方块A, 黑桃Q, 梅花5, 红桃10,
* 梅花Q, 梅花J, 方块J, 梅花K, 方块8, 方块6, 方块10, 红桃7, 方块K, 红桃6, 黑桃2, 黑桃K, 梅花10,
* 红桃8, 方块Q, 红桃Q, 大王, 梅花3, 梅花2, 方块7, 方块9, 方块4, 红桃3, 梅花9, 红桃J, 黑桃8, 红桃2,
* 黑桃6, 红桃A, 黑桃9, 黑桃4, 黑桃J, 黑桃10, 小王, 黑桃3, 黑桃5, 红桃5, 红桃4, 方块2, 方块3, 梅花8]
*/ } public static void swap(List<?> list, int i, int j) {
final List l = list;
l.set(i, l.set(j, l.get(i)));
}
} class Card { public static final int DIAMOND = 0; // 方块(钻石)
public final static int CLUB = 1; // 梅花
public static final int HEART = 2; // 红桃(红心)
public static final int SPADE = 3; // 黑桃(花锄)
public static final int JOKER = 4; // 王 public final static int THREE = 0;
public final static int FOUR = 1;
public final static int FIVE = 2;
public final static int SIX = 3;
public final static int SEVEN = 4;
public final static int EIGHT = 5;
public final static int NINE = 6;
public final static int TEN = 7;
public final static int JACK = 8;// J
public final static int QUEEN = 9;// Q
public final static int KING = 10;// K
public final static int ACE = 11;// A
public final static int DEUCE = 12; //
public final static int BLACK = 13; // 小王
public final static int COLOR = 14;// 大王 /** 花色 0代表方块, 1代表梅花, 2代表红桃, 3代表黑桃,4:王 */
private int suit;
/** 点数 规定: 0代表3, 1代表4, 2代表5,... */
private int rank; public Card() {
} public Card(int suit, int rank) {
// this.rank = rank;
// this.suit = suit;
setRank(rank);
setSuit(suit);
} public int getSuit() {
return suit;
} public void setSuit(int suit) {
if (suit < DIAMOND || suit > JOKER)
throw new RuntimeException("花色超过范围!");
this.suit = suit;
} public int getRank() {
return rank;
} public void setRank(int rank) {
if (rank < THREE || rank > COLOR) {
throw new RuntimeException("点数超过范围!");
}
this.rank = rank;
} private static final String[] RANK_NAMES = { "3", "4", "5", "6", "7", "8",
"9", "10", "J", "Q", "K", "A", "2", "小王", "大王" };
private static final String[] SUIT_NAMES = { "方块", "梅花", "红桃", "黑桃", "" }; // 覆盖Object 类的toStirng() 方法. 实现对象的文本描述
public String toString() {
return SUIT_NAMES[suit] + RANK_NAMES[rank];
} public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (this == obj) {
return true;
}
if (obj instanceof Card) {
Card other = (Card) obj;
return this.rank == other.rank && this.suit == other.suit;
}
return false;
} public int hashCode() {
// return suit*100+rank;
// suit=3= 00000000 00000000 00000000 00000011
// rank=10=00000000 00000000 00000000 00000011
// suit<<16=00000000 00000011 00000000 00000000
// 00000000 00000011 00000000 00000011
return (suit << 16) + rank;// (x<<16)+y
}
}
注意:如果给定一个整型数组,用Arrays.asList()方法将其转化为一个集合类,有两种途径:
1)用List<Integer> list=ArrayList(Arrays.asList(ia)),用shuffle()打乱不会改变底层数组的顺序。
2)用List<Integer> list=Arrays.aslist(ia),然后用shuffle()打乱会改变底层数组的顺序。代码例子如下:
public class Modify {
public static void main(String[] args){
Random rand=new Random(47);
Integer[] ia={0,1,2,3,4,5,6,7,8,9};
List<Integer> list=new ArrayList<Integer>(Arrays.asList(ia));
System.out.println("Before shufflig: "+list);
Collections.shuffle(list,rand);
System.out.println("After shuffling: "+list);
System.out.println("array: "+Arrays.toString(ia));
List<Integer> list1=Arrays.asList(ia);
System.out.println("Before shuffling: "+list1);
Collections.shuffle(list1,rand);
System.out.println("After shuffling: "+list1);
System.out.println("array: "+Arrays.toString(ia)); }
}
结果如下:
Before shufflig: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
After shuffling: [3, 5, 2, 0, 7, 6, 1, 4, 9, 8]
array: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Before shuffling: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
After shuffling: [8, 0, 5, 2, 6, 1, 4, 9, 3, 7]
array: [8, 0, 5, 2, 6, 1, 4, 9, 3, 7]
在第一种情况中,Arrays.asList()的输出被传递给了ArrayList()的构造器,这将创建一个引用ia的元素的ArrayList,因此打乱这些引用不会修改该数组。 但是,如果直接使用Arrays.asList(ia)的结果, 这种打乱就会修改ia的顺序。意识到Arrays.asList()产生的List对象会使用底层数组作为其物理实现是很重要的。 只要你执行的操作 会修改这个List,并且你不想原来的数组被修改,那么你就应该在另一个容器中创建一个副本。
Collections.shuffle()源码分析的更多相关文章
- Collections.shuffle源码阅读
java.util.Collections /** * Randomly permutes the specified list using a default source of * randomn ...
- Java Collections 源码分析
Java Collections API源码分析 侯捷老师剖析了不少Framework,如MFC,STL等.侯老师有句名言: 源码面前,了无秘密 这句话还在知乎引起广泛讨论. 我对教授程序设计的一点想 ...
- 21、Shuffle原理剖析与源码分析
一.普通shuffle原理 1.图解 假设有一个节点上面运行了4个 ShuffleMapTask,然后这个节点上只有2个 cpu core.假如有另外一台节点,上面也运行了4个ResultTask,现 ...
- 【集合框架】JDK1.8源码分析之Collections && Arrays(十)
一.前言 整个集合框架的常用类我们已经分析完成了,但是还有两个工具类我们还没有进行分析.可以说,这两个工具类对于我们操作集合时相当有用,下面进行分析. 二.Collections源码分析 2.1 类的 ...
- Spark源码分析 – Shuffle
参考详细探究Spark的shuffle实现, 写的很清楚, 当前设计的来龙去脉 Hadoop Hadoop的思路是, 在mapper端每次当memory buffer中的数据快满的时候, 先将memo ...
- worker启动executor源码分析-executor.clj
在"supervisor启动worker源码分析-worker.clj"一文中,我们详细讲解了worker是如何初始化的.主要通过调用mk-worker函数实现的.在启动worke ...
- solr源码分析之solrclound
一.简介 SolrCloud是Solr4.0版本以后基于Solr和Zookeeper的分布式搜索方案.SolrCloud是Solr的基于Zookeeper一种部署方式.Solr可以以多种方式部署,例如 ...
- spark 源码分析之五 -- Spark内置RPC机制剖析之一创建NettyRpcEnv
在前面源码剖析介绍中,spark 源码分析之二 -- SparkContext 的初始化过程 中的SparkEnv和 spark 源码分析之四 -- TaskScheduler的创建和启动过程 中的C ...
- RocketMQ 源码分析 —— Message 发送与接收
1.概述 Producer 发送消息.主要是同步发送消息源码,涉及到 异步/Oneway发送消息,事务消息会跳过. Broker 接收消息.(存储消息在<RocketMQ 源码分析 —— Mes ...
随机推荐
- 模拟估算器:scikit-learn Estimator
转载:https://www.toutiao.com/i6606193174010397187/ 当一个数据科学项目刚刚开始时,关键是要尽可能快地走向一个最小可行的产品(MVP).这个MVP将包含最终 ...
- 由一条普通的link引用引发的无数问号,大家能回答的帮忙回答回答吧.
<link type="text/css" rel="stylesheet" href="1.css" /> 对于前台工作者来说 ...
- Hadoop使用场景
Hadoop使用场景: 大数据量存储:分布式存储 日志处理: Hadoop擅长这个 海量计算: 并行计算 ETL:数据抽取到oracle.mysql.DB2.mongdb及主流数据库 使用HBase做 ...
- IDEA设置syso快捷键输出System.out.println();
用Eclipse时间长了, 就习惯之前的快捷键! 当然, IDEA不愧是Java开发的”利器”! 写起代码就是一个字 – “爽”! 建议大家可以去尝试一下! 当然, 在IDEA中输出System.ou ...
- mac mysql中文乱码问题
God,今天看了好多资料,除了让我命令更熟练以外浪费了好多时间. 遇到的问题:写入数据库有中文的时候,显示??? 最后解决办法: 1.打开终端,输入: mysql -u root -p,然后输入mys ...
- HTML|CSS之HTML常用标签
知识内容: 1.标签 2.head内标签 3.body内常用标签 注:本人使用的HTML为HTML5 一.标签 1.标签格式 标签的语法: <标签名 属性1=“属性值1” 属性2=“属性值2”… ...
- 红帽yum源安装报错initscripts-9.49.41-1.el7.x86_64 conflicts redhat-release < 7.5-0.11" ?
https://access.redhat.com/solutions/3425111 环境 Red Hat Enterprise Linux 7 问题 yum fails to apply upda ...
- HTML5 Canvas ( 绘制一片星空 )
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...
- centos配置DNS和ip
Centos6.5 永久修改DNS地址的方法 1.配置ip地址文件 /etc/sysconfig/network-scripts/ifcfg-eth0添加一行 DNS1=8.8.8.8 #手动添 ...
- HtmlRowCreated关于e.Row.Cells[0]的获取和设置
获取采用: cmd2.Parameters.AddWithValue("@xh", e.GetValue("学号").ToString().Trim()); ...