我的BogoSort程序可能存在逻辑错误

时间:2019-05-08 18:13:28

标签: java

对于作业,我必须编写一些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元素数组进行排序的结果是,根据预期结果对数字进行了正确排序。

2 个答案:

答案 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的每个连续调用,为下一次调用产生略有不同的输入。