对于作业,我必须编写一些Bogosort代码,并凭经验确定程序的Big O表示法。
但是,我不确定代码是否有效,因为即使它对int类型的3和4元素数组进行排序,我也不认为它应该在0毫秒内完成。
相反,这花费了5个元素的真正时间(在15分钟之内仍然没有成功的案例),这向我表明该程序可能有问题。由于没有引发任何错误,我相信发现的任何问题都将是逻辑错误。
我尝试在程序上运行IDE调试器。用于bogosort的每种方法似乎都能按预期工作,尽管我无法达到在使用调试器时对数组进行正确排序的情况。
但是,通过将数组的值更改为已经对其进行排序,我能够测试对数组进行排序并成功执行代码的情况。
这似乎表明,如果有问题,则与排序中的逻辑错误有关,排序方法始终无法获得正确的解决方案。
文件如下所示,并带有注释。
对该程序的任何建议都必须与当前结构有关(不添加方法,不使用ArrayLists),因为这是一项家庭作业。
public class BogoSort {
public static void main(String[] args) {
int[] myArray = {20, 142, 115, 120, 140};
//sets start time
long start = System.currentTimeMillis();
bogoSort(myArray);
//sets end time
long end = System.currentTimeMillis();
printArray(myArray);
//print time (end time - start time)
System.out.println((end - start) + "ms");
}
// Places the elements of a into sorted order.
public static void bogoSort(int[] a) {
while(!isSorted(a)){
//calls the shuffle method if it's not sorted
shuffle(a);
}
}
// Returns true if a's elements are in sorted order.
public static boolean isSorted(int[] a) {
for (int i = 0; i < a.length - 1; i++) {
if (a[i] > a[i+1]) {
//returns false if the number in this index is greater than
//the number in the next index aka not sorted
return false;
}
}
//else return true
return true;
}
// Shuffles an array of ints by randomly swapping each
// element with an element ahead of it in the array.
public static void shuffle(int[] a){
Random r = new Random();
for(int i = a.length - 1;i > 0;i--){
//random number between 0 and i
int j = r.nextInt(i);
//calls swap method
swap(a, i, j);
}
}
// Swaps a[i] with a[j].
public static void swap(int[] a, int i, int j) {
//temp variable to hold value of a[i] for swap
int temp = a[i];
a[i] = a[j];
a[j] = temp;
}
public static void printArray(int[] a)
{
for(int i = 0; i < a.length; i++)
{
System.out.println(a[i]);
}
}
}//end of BogoSort class
结果应如下:
20
115
120
140
142
???ms
???如果我正确理解 bogosort的Big O表示法,则该值表示程序运行的时间,可能约为720毫秒。
目前,我还没有得到大于4的数组的结果。
3或4个元素的数组进行排序所需的时间是0 ms,这对我来说有点奇怪,我觉得3个元素应该是24 ms,4个元素是120 ms。
对3或4元素数组进行排序的结果是,根据预期结果对数字进行了正确排序。
答案 0 :(得分:2)
您的随机播放算法由于“ by-by-1”错误而被破坏。如果您使用int[] myArray = {2,1,3};
进行尝试,则会发现它也无法针对3个元素完成。
在处理随机性时,最好使用统计数据而不是盯眼,因为一眼就很难注意到这一点:
$ java BogoSort | head -n 100000 > file
$ sort file | uniq -c
33325 [1, 3, 2]
33315 [2, 1, 3]
33360 [3, 2, 1]
如您所见,您只会在6个可能的排列中生成3个。
如您的注释所示,随机播放时,可以将数组中的每个元素替换为较早的元素。您还需要允许元素保留在原位。您可以通过在选择的索引上加1来完成此操作:
// Shuffles an array of ints by randomly swapping each
// element with an element ahead of it in the array **or leave it in place**.
public static void shuffle(int[] a){
Random r = new Random();
for(int i = a.length - 1;i > 0;i--){
//random number between 0 and i
int j = r.nextInt(i+1); // <-- +1 here to select the current element
//calls swap method
swap(a, i, j);
}
}
现在结果看起来更好了(我对程序进行排序以使其即使在排序时也可以继续打印):
$ sort file | uniq -c
16807 [1, 2, 3]
16579 [1, 3, 2]
16745 [2, 1, 3]
16697 [2, 3, 1]
16361 [3, 1, 2]
16811 [3, 2, 1]
,实际上,它现在可以在0-1毫秒内完成。与预期的阶乘曲线一致,以8个数字运行它需要10毫秒,而10个数字则需要150毫秒。
答案 1 :(得分:1)
accepted answer正确地识别了故障并给出了直接的解决方案。
我试图更深入地研究为什么缺少排列。从该答案建议的起点[2,1,3]
开始,将导致错误的随机播放只能产生两个结果:[1,3,2]
和[3,2,1]
。这已经是一个错误,因为您期望随机播放能够产生6个排列中的任何一个。但是,此外,在不正确的混洗下,这些结果只能在另一次糟糕的混洗迭代中相互产生。
因此,换一种方式考虑,[2,1,3]
改编为[1,2,3]
的唯一方法是允许第三个元素保留在原位。 [1,3,2]
改编为[1,2,3]
的唯一方法是允许第一个元素保留在原位。最后,[3,2,1]
改编为[1,2,3]
的唯一方法是允许第二个元素留在原处。但是该算法不允许元素保留,并且在随机迭代期间任何移动的元素都不会再次移动。
不良的混洗只会产生导致所有元素处于不同位置的排列。 换句话说,它只能产生旋转! 仅适用于3元素情况
因此,如果起始点不是排序数组的旋转,则算法将永远不会终止。
在评论中,我建议了另一种shuffle
实现:
public static void shuffle(int[] a){
Random r = new Random();
int x = r.nextInt(a.length);
for(int i = a.length-1;i > 0;i--){
int j = r.nextInt(i);
if (j < x) break;
swap(a, i, j);
}
}
但是,此shuffle
的弱点在于它本身仍然缺乏生成任何可能排列的能力。 bogosort 使用此实现最终查看所有可能排列的能力取决于对shuffle
的每个连续调用,为下一次调用产生略有不同的输入。