在网站上我们经常会看到关键字云(Word Cloud)和标签云(Tag Cloud),用于表明这个关键字或标签是经常被查阅的,而且还可以看到这些标签的动态运动,每次刷新都会有不一样的关键字或便签,让浏览者觉得这个网站的访问量非常大,短短的几分钟就有这么多的搜索量。这是怎么实现的呢?其实非常简单:先从数据库中读出标签,然后使用随机数打乱,每次都产生不同的顺序,嗯,确实能让浏览者感觉到我们的标签云顺序在变——浏览者多嘛!但是,对于乱序处理我们有哪些方法呢?
下面给出一个大家都会想到的方法:
public <T> void shuffle1(List<T> list) {
int size = list.size();
Random random = new Random();
for(int i = 0; i < size; i++) {
// 获取随机位置
int randomPos = random.nextInt(size);
// 当前元素与随机元素交换
T temp = list.get(i);
list.set(i, list.get(randomPos));
list.set(randomPos, temp);
}
}
很简单,实现方法也很多,但有更简单的实现方法:
public <T> void shuffle2(List<T> list) {
int size = list.size();
Random random = new Random();
for(int i = 0; i < size; i++) {
// 获取随机位置
int randomPos = random.nextInt(size);
// 当前元素与随机元素交换
Collections.swap(list, i, randomPos);
}
}
上面使用了Collections的swap方法,该方法会交换两个位置的元素值,不用我们自己写交换代码了,是不是更简单呢?
其实,我想说,还有更更简单的方法,如下:
public <T> void shuffle3(List<T> list) {
// 打乱顺序
Collections.shuffle(list);
}
这才是我们想要的结果,就这一句话即可打乱一个列表的顺序,不用我们费尽心思的遍历、替换元素了!
现在来测试一下,是不是都能成功实现打乱顺序呢?下面给出完整源代码:
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;
/**
* 打乱列表中数据元素的三种实现方法
*/
public class ShuffleTest {
// 打乱列表实现方法1
public <T> void shuffle1(List<T> list) {
int size = list.size();
Random random = new Random();
for(int i = 0; i < size; i++) {
// 获取随机位置
int randomPos = random.nextInt(size);
// 当前元素与随机元素交换
T temp = list.get(i);
list.set(i, list.get(randomPos));
list.set(randomPos, temp);
}
}
// 打乱列表实现方法2
public <T> void shuffle2(List<T> list) {
int size = list.size();
Random random = new Random();
for(int i = 0; i < size; i++) {
// 获取随机位置
int randomPos = random.nextInt(size);
// 当前元素与随机元素交换
Collections.swap(list, i, randomPos);
}
}
// 打乱列表实现方法3
public <T> void shuffle3(List<T> list) {
// 打乱顺序
Collections.shuffle(list);
}
// 打印列表
public <T> void print(List<T> list) {
for(T t : list) {
System.out.print(t + " ");
}
System.out.println("\n");
}
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ShuffleTest st = new ShuffleTest();
List<String> tagClouds = new ArrayList<String>(6);
// 一般从数据库中读取,这里仅以测试为目的
tagClouds.add("计算机");
tagClouds.add("Java");
tagClouds.add("编程");
tagClouds.add("C/C++");
tagClouds.add("操作系统");
tagClouds.add("数据库");
System.out.println("原顺序:");
st.print(tagClouds);
st.shuffle1(tagClouds);
System.out.println("打乱顺序一:");
st.print(tagClouds);
st.shuffle2(tagClouds);
System.out.println("打乱顺序二:");
st.print(tagClouds);
st.shuffle3(tagClouds);
System.out.println("打乱顺序三:");
st.print(tagClouds);
}
}
输出结果如下:
我们一般很少用到shuffle这个方法,那它可以用在什么地方呢?
(1)可以用在程序的“伪装”上
比如我们例子中的标签云,或者是游戏中的打怪、修行、群殴时宝物的分配策略。
(2)可以用在抽奖程序中
比如年会的抽奖程序,先使用shuffle把员工顺序打乱,每个员工的中奖几率就是相等的了,然后就可以抽取第一名、第二名。
(3)可以用在安全传输方面
比如发送端发送一组数据,先随机打乱顺序,然后加密发送,接收端解密,然后自行排序,即可实现即使是相同的数据源,也会产生不同密文的效果,加强了数据的安全性。
import lombok.extern.slf4j.Slf4j;
import org.junit.Test;
import org.springframework.util.StopWatch;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* @author: tangcheng
* @description:
* @since: Created in 2018/08/07 11:01
*/
@Slf4j
public class CollectShuttleTest {
/**
* 从1000个中去掉100个,总耗时18ms
* 混淆后的数据,没有发现明显的问题
*/
@Test
public void shuffleTest() {
List<Integer> total = new ArrayList<>();
for (int i = 0; i < 1000; i++) {
total.add(i);
}
StopWatch stopWatch = new StopWatch("Collections.shuffle()");
int count = 100;
List<Integer> winnerList = new ArrayList<>(100);
for (int i = 0; i < count; i++) {
stopWatch.start("time_" + i);
Collections.shuffle(total);
int index = total.size() - 1;
Integer winner = total.remove(index);
winnerList.add(winner);
log.info("taskName:{},winner:{}", i, winner);
stopWatch.stop();
}
log.info("winnerList:{},stopWatch.prettyPrint():{}", winnerList, stopWatch.prettyPrint());
/**
* winnerList:[
* 163, 905, 954, 828, 387, 217, 272, 662, 753, 160,
* 636, 629, 132, 318, 655, 388, 501, 879, 625, 515,
* 339, 897, 497, 959, 819, 654, 71, 984, 356, 256,
* 539, 330, 888, 643, 928, 10, 213, 878, 935, 206,
* 53, 875, 437, 422, 997, 464, 276, 65, 451, 732,
* 432, 154, 385, 955, 161, 719, 352, 383, 37, 853,
* 675, 696, 646, 223, 742, 807, 76, 738, 415, 516,
* 890, 656, 610, 910, 80, 7, 561, 548, 947, 390,
* 949, 236, 382, 338, 112, 240, 162, 642, 754, 571,
* 8, 802, 532, 410, 372, 462, 880, 38, 744, 360
* ],
* stopWatch.prettyPrint():StopWatch 'Collections.shuffle()': running time (millis) = 18
* -----------------------------------------
* ms % Task name
* -----------------------------------------
* 00007 039% time_0
* 00000 000% time_1
* 00000 000% time_2
* 00001 006% time_3
* 00000 000% time_4
* 00000 000% time_5
* 00000 000% time_6
* 00000 000% time_7
* 00000 000% time_8
* 00000 000% time_9
* 00000 000% time_10
* 00000 000% time_11
* 00001 006% time_12
* 00000 000% time_13
* 00000 000% time_14
* 00000 000% time_15
* 00000 000% time_16
* 00000 000% time_17
* 00000 000% time_18
* 00000 000% time_19
* 00000 000% time_20
* 00000 000% time_21
* 00000 000% time_22
* 00000 000% time_23
* 00001 006% time_24
* 00000 000% time_25
* 00000 000% time_26
* 00000 000% time_27
* 00001 006% time_28
* 00000 000% time_29
* 00001 006% time_30
* 00000 000% time_31
* 00000 000% time_32
* 00000 000% time_33
* 00000 000% time_34
* 00000 000% time_35
* 00000 000% time_36
* 00000 000% time_37
* 00000 000% time_38
* 00000 000% time_39
* 00000 000% time_40
* 00001 006% time_41
* 00000 000% time_42
* 00000 000% time_43
* 00000 000% time_44
* 00000 000% time_45
* 00000 000% time_46
* 00000 000% time_47
* 00000 000% time_48
* 00000 000% time_49
* 00000 000% time_50
* 00001 006% time_51
* 00000 000% time_52
* 00000 000% time_53
* 00000 000% time_54
* 00000 000% time_55
* 00000 000% time_56
* 00000 000% time_57
* 00000 000% time_58
* 00000 000% time_59
* 00000 000% time_60
* 00000 000% time_61
* 00000 000% time_62
* 00001 006% time_63
* 00000 000% time_64
* 00000 000% time_65
* 00001 006% time_66
* 00000 000% time_67
* 00000 000% time_68
* 00000 000% time_69
* 00000 000% time_70
* 00000 000% time_71
* 00000 000% time_72
* 00000 000% time_73
* 00000 000% time_74
* 00000 000% time_75
* 00000 000% time_76
* 00001 006% time_77
* 00000 000% time_78
* 00000 000% time_79
* 00000 000% time_80
* 00000 000% time_81
* 00000 000% time_82
* 00000 000% time_83
* 00000 000% time_84
* 00000 000% time_85
* 00000 000% time_86
* 00000 000% time_87
* 00000 000% time_88
* 00000 000% time_89
* 00000 000% time_90
* 00000 000% time_91
* 00001 006% time_92
* 00000 000% time_93
* 00000 000% time_94
* 00000 000% time_95
* 00000 000% time_96
* 00000 000% time_97
* 00000 000% time_98
* 00000 000% time_99
*/
}
}