FisherYates shuffle 基本思想(Knuth shuffle ):
打乱包含 n 个元素的数组 a(索引 0..n-1):
对于 i 从 n − 1 降到 1 做
j ← 0 ≤ j ≤ i 的随机整数
交换 a[j] 和 a[i]
JDK来源代码如下:
/**
* 将列表中的每个元素移动到列表中的随机新位置
* 使用指定的随机数生成器。
*
* @参数列表
* 待洗牌的列表
* @参数随机
* 随机数生成器
*
* @抛出不支持的操作异常
* 不支持替换列表中的元素时
*/
@SuppressWarnings(“未选中”)
公共静态无效洗牌(列表<?>列表,随机随机){
if (!(随机访问的列表实例)) {
Object[] 数组 = list.toArray();
for (int i = array.length - 1; i > 0; i--) {
int索引 = random.nextInt(i + 1);
如果(索引 < 0){
索引=-索引;
}
对象温度=数组[i];
数组[i] = 数组[索引];
数组[索引] = 临时;
}
整数 i = 0;
ListIterator<Object> it = (ListIterator<Object>) 列表
.listIterator();
while (it.hasNext()) {
它.下一个();
it.set(数组[i++]);
}
} 别的 {
List<对象> rawList = (List<对象>) 列表;
for (int i = rawList.size() - 1; i > 0; i--) {
int索引 = random.nextInt(i + 1);
如果(索引 < 0){
索引=-索引;
}
rawList.set(index, rawList.set(i, rawList.get(index)));
}
}
}
公共静态无效主(最终字符串参数[]){
对象更改温度;
List<Integer> numList = new ArrayList<Integer>();
List<Integer> firstList = new ArrayList<Integer>();
List<Integer> SecondList = new ArrayList<Integer>();
List<Integer>thirdList = new ArrayList<Integer>();
List<Integer> FourthList = new ArrayList<Integer>();
for (int i = 1; i <= 100000; i++) {
numList.add(i);
第一个列表.add(i);
第二个列表.add(i);
thirdList.add(i);
FourthList.add(i);
}
// 第一次随机播放,使用changeTemp
getStartTime();
int randInt = 0;
for (int i = 0, length = firstList.size(); i < length; i++) {
randInt = getRandom(i,firstList.size());
更改温度=firstList.get(i);
firstList.set(i,firstList.get(randInt));
firstList.set(randInt, javaShuffle.temp);
}
getEndTime("第一次随机播放时间");
// 第二次洗牌,交换列表
getStartTime();
for (int i = 0, length = secondaryList.size(); i < length; i++) {
randInt = getRandom(i, secondaryList.size());
secondaryList.set(i, secondaryList.set(randInt, secondaryList.get(i)));
}
getEndTime("第二次洗牌运行时间");
// 第三次洗牌,更改生成随机整数
getStartTime();
Object[] tempArray =thirdList.toArray();
随机兰特 = new Random();
整数 j = 0;
for (int i = tempArray.length - 1; i > 0; i--) {
j = rand.nextInt(i + 1);
thirdList.set(i,thirdList.set(j,thirdList.get(i)));
}
getEndTime("第三次洗牌运行时间");
// 第四次shuffle,模拟java shuffle
getStartTime();
随机随机 = new Random();
if (!(RandomAccess 的第四个列表实例)) {
Object[] array = FourthList.toArray();
for (int i = array.length - 1; i > 0; i--) {
int索引 = random.nextInt(i + 1);
如果(索引 < 0){
索引=-索引;
}
对象温度=数组[i];
数组[i] = 数组[索引];
数组[索引] = 临时;
}
整数 i = 0;
ListIterator<Integer> it = (ListIterator<Integer>) FourthList.listIterator();
while (it.hasNext()) {
it.next();
it.set((整数)数组[i++]);
}
} 别的 {
List<Integer> rawList = (List<Integer>) FourthList;
for (int i = rawList.size() - 1; i > 0; i--) {
int索引 = random.nextInt(i + 1);
如果(索引 < 0){
索引=-索引;
}
rawList.set(index, rawList.set(i, rawList.get(index)));
}
}
getEndTime("第四次shuffle运行时间");
// java 随机播放
getStartTime();
Collections.shuffle(numList);
getEndTime("java shuffle 运行时间");
}
公共静态无效交换(int a,int b){
javaShuffle.temp = a;
a = b;
b = javaShuffle.temp;
}
公共静态 int getRandom(最终 int 低,最终 int 高){
return (int) (Math.random() * (高 - 低) + 低);
}
公共静态无效 getStartTime() {
javaShuffle.start = System.nanoTime();
}
公共静态无效 getEndTime(最终字符串 s) {
javaShuffle.end = System.nanoTime();
System.out.println(s + ": " + (javaShuffle.end - javaShuffle.start) + "ns");
}
}
如果数值较小,例如100000级别,则输出大概是:
第一次随机播放运行时间:85029499ns
第二次随机播放运行时间:80909474ns
第三次随机播放运行时间:71543926ns
第四次随机播放运行时间:76520595ns
java shuffle 运行时间:61027643ns
第一次随机播放运行时间:82326239ns
第二次随机播放运行时间:78575611ns
第三次随机播放运行时间:95009632ns
第四次随机播放运行时间:105946897ns
java shuffle 运行时间:90849302ns
第一次随机播放运行时间:84539840ns
第二次随机播放运行时间:85965575ns
第三次随机播放运行时间:101814998ns
第四次随机播放运行时间:113309672ns
java shuffle 运行时间:35089693ns
第一次随机播放运行时间:87679863ns
第二次随机播放运行时间:79991814ns
第三次随机播放运行时间:73720515ns
第四次随机播放运行时间:78353061ns
java shuffle 运行时间:64146465ns
第一次随机播放运行时间:84314386ns
第二次随机播放运行时间:80074803ns
第三次随机播放运行时间:74001283ns
第四次随机播放运行时间:79931321ns
java shuffle 运行时间:86427540ns
第一次随机播放运行时间:84315523ns
第二次随机播放运行时间:81468386ns
第三次随机播放运行时间:75052284ns
第四次随机播放运行时间:79461407ns
java shuffle 运行时间:66607729ns
如果是10000000级别,大概如下:
第一次随机播放运行时间:2115703288ns
第二次随机播放运行时间:3114045871ns
第三次随机播放运行时间:4664426798ns
第四次随机播放运行时间:2962686695ns
java shuffle 运行时间:3246883026ns 第一次 shuffle 运行时间:2165398466ns
第二次随机播放运行时间:3129558913ns
第三次随机播放运行时间:4147859664ns
第四次随机播放运行时间:2911849942ns
java shuffle 运行时间:4311703487ns 第一次 shuffle 运行时间:2227462247ns
第二次随机播放运行时间:3279548770ns
第三次随机播放运行时间:4704344954ns
第四次随机播放运行时间:2942635980ns
java shuffle 运行时间:3933172427ns 第一次 shuffle 运行时间:2200158789ns
第二次随机播放运行时间:3172666791ns
第三次随机播放运行时间:4715631517ns
第四次随机播放运行时间:2950817535ns
java shuffle 运行时间:3387417676ns 第一次 shuffle 运行时间:2201124449ns
第二次随机播放运行时间:3203823874ns
第三次随机播放运行时间:4179926278ns
第四次随机播放运行时间:2913690411ns
java shuffle 运行时间:3571313813ns 第一次 shuffle 运行时间:2163053190ns
第二次随机播放运行时间:3073889926ns
第三次随机播放运行时间:4493831518ns
第四次随机播放运行时间:2852713887ns
java shuffle运行时间:3773602415ns
可以看出,第一种方法速度最快,而第四种最慢。java自带shuffle速度也不理想。
在进行大数据处理的时候,如果使用java库效率较低时,可以考虑使用其他方式。