【问题标题】:Unable to perfectly implement QuickSort无法完美实现快速排序
【发布时间】:2016-02-20 17:18:46
【问题描述】:

我正在尝试在 java 中编写一个简单的方法,该方法将在 int[] 上执行快速排序,但我不断得到一个在我的结果中不合适的值。

任何帮助了解我哪里出错了,我们将不胜感激。以下是我的代码:

public static void quickSort(int[] arr, int left, int right){
    if (left < right){
        int p = partition(arr, left, right);
        quickSort(arr, left, p-1);
        quickSort(arr, p+1, right);
    }
}

public static int partition(int[] arr, int left, int right){
    int pivot = arr[left];
    int l = left+1;
    int r = right;
    while (l < r){
        while (l<right && arr[l] < pivot){
            l++;
        }
        while (r>left && arr[r] > pivot){
            r--;
        }
        if (l < r){
            int temp = arr[l];
            arr[l] = arr[r];
            arr[r] = temp;
        }
    }
    arr[left] = arr[r];
    arr[r] = pivot;         
    return r;
}

【问题讨论】:

  • 如果right 等于left+1 怎么办?这两个元素无需任何关键比较即可交换。 (哦,如果枢轴在循环之后一直保持在arr[left] 中,则比较r&gt;left 是多余的。)

标签: java arrays algorithm sorting quicksort


【解决方案1】:

Hoare 分区方案在快速排序调用中使用 p 和 p+1。我将一个工作的 C 程序转换为 Java。我将枢轴切换到中间,因此排序或反向排序的数组不是最坏的情况。

public static void quickSort(int[] arr, int left, int right){
    if (left < right){
        int p = partition(arr, left, right);
        quickSort(arr, left, p);
        quickSort(arr, p+1, right);
    }
}

public static int partition(int[] arr, int left, int right){
    int pivot = arr[(left+right)/2];
    int l = left-1;
    int r = right+1;
    while (true){
        while (arr[++l] < pivot);
        while (arr[--r] > pivot);
        if (l >= r)
            break;
        int temp = arr[l];
        arr[l] = arr[r];
        arr[r] = temp;
        }
    }
    return r;
}

【讨论】:

    【解决方案2】:

    我改变了你的分区方法。我尝试做一些小的改动,主要是为了打破循环。

    public static int partition(int[] arr, int left, int right) {
        int pivot = arr[left];
        int l = left ;
        int r = right+1;
        while (true) {
            while (arr[++l] < pivot) {
                if (l >= right)
                    break;
            }
            while (arr[--r] > pivot) {
                if (r <= left)
                    break;
            }
            if (l >= r)
                break;
            int temp = arr[l];
            arr[l] = arr[r];
            arr[r] = temp;
        }
        arr[left] = arr[r];
        arr[r] = pivot;
        return r;
    }
    

    我测试了以下场景并且它正在工作。

    int[] arr = { 9, 5, 10, 8, 2, 3, 4, 7, 6, 1 };
    int[] arr = { 9, 5, 10, 8, 2, 9, 5, 10, 8, 2 };
    quickSort(arr, 0, arr.length - 1);
    System.out.println(Arrays.toString(arr));
    

    【讨论】:

    • 谢谢你。我无法理解为什么会有所作为,但我会尝试在我的代码中实现它,看看它是否可以。
    • 添加 break 语句以退出 while 循环似乎可以做到这一点。不知道为什么会这样。
    • 之前的代码无法检查边界条件,何时中断或继续。三个 break 语句就是这样做的。以前的代码会同时进行值检查和边界检查,但新代码会检查值的有效性,然后检查边界以中断或继续。
    • @rcgldr 我更改了 break 语句,你能检查一下吗?我测试了使用你的输入。
    • @UgurBasak - 我发布了一个答案,但我从 C 转换为 Java。也许你可以测试一下。这本质上是 wiki Hoare partition scheme
    【解决方案3】:

    这两行是可疑的:

    quickSort(arr, p+1, right);

    int l = left+1;

    在取右侧分区时,是否跳过了数组的第一个元素?添加一些示例测试用例及其输出将很有用。

    【讨论】:

    • 据我所知,我没有跳过任何值。当我使用调试器时,我还注意到它最初对其进行了正确排序,然后再次切换它们。至少在第二个测试用例中。这是我尝试过的一个测试用例: 输入数组:8 5 9 10 12 9 6 12 13 19 22 14 17 21 5 1 4 3 2 结果:1 2 3 4 5 5 6 8 9 9 10 12 12 13 17 14 19 21 22 第二个测试用例: 输入数组: 8 5 9 10 12 7 6 13 19 22 14 17 21 5 1 4 3 2 结果: 1 2 3 4 5 5 7 6 8 9 10 12 13 14 17 19 21 22跨度>
    【解决方案4】:

    您的代码是完美的,但请确保为方法 quickSort 提供正确的值。

            int[] arr = .....;
            int left = 0;
            int right = arr.length - 1;
    
      public static void quickSort(int[] arr, int left, int right){
    

    【讨论】:

    • 这正是我提供的参数。
    猜你喜欢
    • 1970-01-01
    • 2023-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-01-31
    • 2013-08-09
    • 2016-01-10
    相关资源
    最近更新 更多