我想生成array a
的排列,我不想使用java.util.Collections()
等实用功能。
排列应该随机化并且每个排列都应该可能发生 - 但是不需要均匀分布的概率。
以下代码实现了这一点 - 但性能不佳:
// array holding 1,...,n
// initialized somewhere else
int[] a = new int[N];
for (int i = 0; i < a.length ; i++) {
int r = (int) (Math.random() * (i+1));
swap(r,i,a);
}
private static void swap(int j, int k, int[] array){
int temp = array[k];
array[k] = array[j];
array[j] = temp;
}
问题:
是否有可能减少用于生成排列的随机数总数?
答案 0 :(得分:4)
如果有人对Knuth shuffle进行了改进,我会感到惊讶。这是O(n)。
需要O(n)随机数,这对我来说还不够。
This citation声称有一个O(n log n)算法。
我们都希望看到O(log n)或O(1)。
O(log n)算法通常依赖于“分而治之”的二分法,这会让人想到切割甲板并将每一半分开。
但我不禁想到,如果可以使用更快的算法,Knuth就会找到它。
答案 1 :(得分:2)
长度为n的序列有n!排列。如果每个都需要进行排列,那么每个排列都必须有一系列随机数。
要随机置换长度为n的数组,您可以生成1..n范围内的单个随机数!均匀随意。这标识了单个排列,然后您可以应用它。
您可以改进您的问题,询问需要多少随机位。通过相同的论证,那将是log(n!)。为了让您了解该函数的渐近行为,请考虑:
设n&gt; 3:
n = log(2 ^ n)&lt; log(n!)&lt; log(n ^ n)= n * log(n)
因此n个随机位不够(对于n> 3)。实际上,可以证明log(n!)不在O(n)中。
答案 2 :(得分:1)
我能想到的唯一可能的优化是使随机数生成器更快。一个简单的解决方案是首先生成随机整数:
import java.util.Random;
Random rand = new Random();
for (int i = 0; i < a.length ; i++) {
swap(rand.nextInt(i+1), i, a);
}
...
或者,您可以发明一种更快或更少的随机数生成方式(均匀分布或不分配,适合您的需要)。但是,你无法克服O(n)限制。