Shuffle算法学习
Fisher–Yates Shuffle算法
- 思想:算法思想就是从原始数组中随机抽取一个新的数字到新数组中
- 复杂度:
O(n^2)
- 实现
private static final int[] shuffledNums = new int[]{...};
/**
* Fisher-Yates Shuffle算法
* @return
*/
public static int[] shuffle() {
Random random = new Random();
List<Integer> list = new ArrayList<>();
//1.初始化新数组
for (int i = 0; i < shuffledNums.length; i++) {
list.add(shuffledNums[i]);
}
int x, j = 0;
//2.从还没处理的数组(假如还剩k个)中,随机产生一个[0, k)之间的数字p (假设数组从0开始)
//3.剩下的k个数中把第p个数取出
//重复2和3,直到数字取完
for (int i = list.size() - 1; i >= 0; i = list.size() - 1) {
x = random.nextInt(i + 1);
shuffledNums[j++] = list.get(x);
list.remove(x);
}
//返回的数组为打乱的数组
return shuffledNums;
}
Knuth-Durstenfeld Shuffle算法
- 思想:Fisher–Yates Shuffle的改进,每次从未处理的数据中随机取出一个数字,然后把该数字放在数组的尾部,即数组尾部存放的是已经处理过的数字。在原始数组上对数字进行交互,省去了额外
O(n)
的空间。 - 复杂度:
O(n)
- 实现
private static final int[] shuffledNums = new int[]{...};
public static int[] shuffle() {
Random random = new Random();
int x, t;
//1. 从未处理的数据中随机获取一个数字
//2. 把该数字放在数组的尾部,即尾部的数据已被处理了
//3. 从尾部开始处理,当处理完index=0的数据,得到洗牌后的数据
for (int i = shuffledNums.length - 1; i > 0; i--) {
x = random.nextInt(i + 1);
t = shuffledNums[i];
shuffledNums[i] = shuffledNums[x];
shuffledNums[x] = t;
}
return shuffledNums;
}