方式:
1.暴力法
将所有的数放入一个容器内,随机取数值,以此形成一个数组。
就和概率论中不放回抽奖一样 我们是可以得到选中每一个球的概率是:
1
n
\frac{1}{n}
n1
对于实现这个算法来说我们需要将所有的数组取一个随机数并%
上数组的当前最大值,然后移除该数据。
获取当前的值随机元素方式:
public int[] shuffle() {
List<Integer> aux = getArrayCopy();
for (int i = 0; i < array.length; i++) {
int removeIdx = rand.nextInt(aux.size());
array[i] = aux.get(removeIdx);
aux.remove(removeIdx);
}
return array;
}
如此这般可以将一次取出元素组成一个随机的数组。
分析:
该算法的由于每一次都要remove 移动一遍,所以成本是
σ
(
[
n
2
]
)
\sigma \left ( \left [ n^{2} \right ] \right )
σ([n2])
空间上需要有另一个数据来存储数据所以空间复杂度是n。
2.Fisher-Yates
既然这样我们是否可以通过某些优化从而避免较少的删除上的移动呢?
我们可以选择交换相关的元素从而使得数组变得更加随机,即从第一个元素开始,从后面的数中随机挑选一个数进行交换。以此类推。
代码如下:
public int[] shuffle() {
for (int i = 0; i < array.length; i++) {
swapAt(i, randRange(i, array.length));
}
return array;
}
因为是从头到尾扫描一遍 因此该算法的时间负责度为n。