当前位置: 首页 > 知识库问答 >
问题:

就地快速排序w/最后一个元素枢轴?

王季萌
2023-03-14

我试图实现就地快速排序,最后一个元素作为我的支点。下面附上我的代码

public static void main(String[] args){
        int[] input = {3,2,4,6,10,1,9,7,5};
        quickSort(input, 0, input.length-1);
    }
    public static void swap(int[] array, int i, int j) {
        int tmp = array[i];
        array[i] = array[j];
        array[j] = tmp;
    }

    public static int partition(int arr[], int left, int right) {
        int pivot = arr[right];
        int high = right-1;

        while(left < high){
            while(arr[left] < pivot){
                left++;
            }
            while(arr[high] > pivot){
                high--;
            }
            swap(arr,left, high);
            left++;
            high--;
        }
        swap(arr, left, pivot);
        System.out.println(Arrays.toString(arr));
        return left;
    }

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

出于某种原因,我的代码给了我一个IndexOutOfBounds异常,它不能准确地对数组排序。我不知道为什么会出现这个错误。

如果我理解正确,我们应该把最后一个元素作为我们的轴心。然后,我们将左指针向右迭代,直到找到一个大于枢轴的元素。之后,我们从右侧(继续向左移动)执行相同的操作,直到找到一个小于轴的元素。然后我们交换这些元素,继续做同样的事情。

最后,当左/右指针相同时,我们用枢轴交换中心值。

这是正确的思考方式吗?如果是,我的代码有哪些错误?任何帮助都将不胜感激

共有2个答案

穆承运
2023-03-14

在假设最终数组元素是最小元素的情况下跟踪这段代码。调整高的循环会不断地递减高,因为彼此的数组元素比枢轴大,所以最终高的会从数组的前面掉下来,导致你的越界访问。

要解决此问题,请在该循环中添加另一个复选框,以确保您没有出现左高交叉。然后,您可能需要添加一些额外的逻辑,以便将其作为特例处理。

林彬
2023-03-14

有几个错误:

>

  • 向左添加

    检查arr[高]

    swap(arr,左,枢轴) 是错误的。您应该使用位置(而不是值)与轴交换左侧。它应该是swap(arr、左、右)

    您应该选中左侧的

    修复这些错误时,代码应如下所示:

        public static void main(String[] args){
            int[] input = {3,2,4,6,10,1,9,7,5};
            quickSort(input, 0, input.length-1);
        }
        public static void swap(int[] array, int i, int j) {
            int tmp = array[i];
            array[i] = array[j];
            array[j] = tmp;
        }
    
        public static int partition(int arr[], int left, int right) {
            int pivot = arr[right];
            int high = right;
    
            while(left < high){
                while(left < high && arr[left] < pivot){
                    left++;
                }
                while(left < high && arr[high] >= pivot){
                    high--;
                }
                swap(arr,left, high);
            }
            swap(arr, left, right);
            System.out.println( Arrays.toString(arr));
            return left;
        }
    
        public static void quickSort(int arr[], int left, int right) {
            if( left < right)
            {
                int index = partition(arr, left, right);
                quickSort(arr, left, index - 1);
                quickSort(arr, index, right);
            }
        }
    

  •  类似资料:
    • 尝试使用Hoare分区方案实现快速排序,但我遇到了一个问题,即无论数组大小如何,更改pivot的索引都会导致溢出。代码: 这个实现选择低索引(这里名为min)作为轴心元素,这样做很好。但是,将pivot元素更改为任何其他索引都会导致StackOverflow错误,而与正在排序的数组的大小无关。(错误参考第3行,其中调用了partition())我最好在(min,max)范围内随机选择pivot元素

    • 因为最坏情况下的快速排序复杂度为O(n^2) 在递增顺序的情况下,当pivot选择第一个或最后一个元素时,它给出了正确的最坏情况复杂度O(n^2),因为树的一个子元素总是空的 但是当枢轴选择中间时,我感到困惑?它将树分成两半,使其复杂性O(n.logn) 假设10 20 30 40 50 60 70枢轴=40 (10 20 30 ) 40 (50 60 70) 左侧枢轴20,右侧枢轴60 (10)

    • 我在一些地方读到,如果我们不选择第一个或最后一个元素作为轴心,我们应该在分区开始之前首先将其与第一个或最后一个位置交换。所以我尝试了一个例子,我用这个算法得到了正确的分区https://www.cs.auckland.ac.nz/software/AlgAnim/qsort1a.html 此分区方法使用左指针和右指针。它将左指针移向中心,直到找到大于轴的图元。然后将右指针移向中心,直到找到一个小于

    • 返回一个数组中除了最后一个元素以外的所有元素。 使用 arr.slice(0,-1) 返回排除了最后一个元素的数组。 const initial = arr => arr.slice(0, -1); initial([1, 2, 3]); // [1,2]

    • 我正在读关于快速排序的书,看不同的实现,我正试着去想一些事情。 在这个实现中(当然可以),枢轴被选为中间元素,然后左右指针相应地向右和向左移动,将元素交换到围绕枢轴的分区中。 我正在尝试数组[4,3,2,6,8,1,0]。 在第一个分区上,pivot为6,并且所有左侧元素都已小于6,因此左指针将停止在pivot处。在右侧,我们将0与6交换,然后1与8交换,因此在第一次迭代结束时,数组将如下所示:

    • 快速排序是由东尼·霍尔所发展的一种排序算法。在平均状况下,排序 n 个项目要 Ο(nlogn) 次比较。在最坏状况下则需要 Ο(n2) 次比较,但这种状况并不常见。事实上,快速排序通常明显比其他 Ο(nlogn) 算法更快,因为它的内部循环(inner loop)可以在大部分的架构上很有效率地被实现出来。 快速排序使用分治法(Divide and conquer)策略来把一个串行(list)分为两