Java Quickselect实现不起作用

Java Quickselect实现不起作用,java,algorithm,quicksort,quickselect,Java,Algorithm,Quicksort,Quickselect,我试图编写代码来确定数组中最小的n个项。很遗憾,我正在为此挣扎。根据我当年大学课本上的算法,这看起来是正确的。然而,很明显我做错了什么,因为它给了我一个堆栈溢出异常 我的做法是: 将轴心点设置为start+(end start)/2(而不是start+end/2以防止溢出) 使用此位置的整数作为我比较所有内容的轴心 迭代并交换围绕此轴的所有内容,以便对内容进行排序(相对于轴排序) 如果n==pivot,那么我认为我完成了 否则,如果我想要4个最小的元素,例如pivot是3,那么我需要查看右侧(如

我试图编写代码来确定数组中最小的n个项。很遗憾,我正在为此挣扎。根据我当年大学课本上的算法,这看起来是正确的。然而,很明显我做错了什么,因为它给了我一个堆栈溢出异常

我的做法是:

  • 将轴心点设置为start+(end start)/2(而不是start+end/2以防止溢出)
  • 使用此位置的整数作为我比较所有内容的轴心
  • 迭代并交换围绕此轴的所有内容,以便对内容进行排序(相对于轴排序)
  • 如果n==pivot,那么我认为我完成了
  • 否则,如果我想要4个最小的元素,例如pivot是3,那么我需要查看右侧(如果我想要第二个最小的元素,则需要查看左侧)
  • -

    publicstaticvoidmain(字符串[]args){
    int[]元素={30,50,20,10};
    快速选择(要素3);
    }
    私有静态int quickSelect(int[]元素s2,int k){
    返回quickSelect(elements2,k,0,elements2.length-1);
    }
    私有静态int quickSelect(int[]元素、int k、int开始、int结束){
    int pivot=start+(end-start)/2;
    int中点=元素[轴];
    int i=开始,j=结束;
    而(i中点){
    j--;
    }
    
    如果(i这无法解决问题,但您的代码有几个问题:

    • 如果您不检查istart,在某些情况下可能会跑出边界
    • <>你选择你的支点在子数组的中间,但是没有任何证据证明它在分区过程中不会改变位置。然后,用旧的枢轴位置检查k==枢轴,它显然不能工作。

    希望这能有所帮助。

    好吧,所以我做的第一件事就是修改如何获得轴/分区点。正如T.Claverie指出的,缺点是我使用的轴在技术上不是轴,因为元素的位置在分区阶段会发生变化

    实际上,我将分区代码重写为它自己的方法,如下所示

    我选择第一个元素(开始时)作为轴心,并在其前面创建一个“部分”,其中项目少于此轴心。然后,我将轴心的值与值<轴心部分中的最后一个项目交换。我将最终索引作为轴心点返回

    这可以进一步清理(创建单独的交换方法)

    private static int getPivot(int[]元素,int开始,int结束){
    int pivot=开始;
    int-lessThan=开始;
    
    对于(int i=start;i您的第一个要点绝对是一个很好的实践,但我看不到任何情况下会出现这种失败。我也不记得了,但几个月前我使用类似的方法实现了快速排序,我记得当这些语句丢失时我遇到了麻烦。尽管它可能特定于我的实现。请参阅我的更新版本下面的解决方案。您的回答非常有用。关于如何对上面的数组进行分区,还有一个问题。对于值{30,50,20,10},pivot从1开始…30保持不变,左侧计数器增加到50,与10交换-正如您所说,假定的pivot移动…但是,例程以30,10,20,50结束…即使10是pivot或50是pivot,左侧也没有小于pivot的所有值。失败。请至少解释一下为什么如果你将否决一个有效的问题。
    public static void main(String[] args) {
        int[] elements = {30, 50, 20, 10};
        quickSelect(elements, 3);
    }
    
    private static int quickSelect(int[] elements2, int k) {
        return quickSelect(elements2, k, 0, elements2.length - 1);
    }
    
    private static int quickSelect(int[] elements, int k, int start, int end) {
        int pivot = start + (end - start) / 2;
        int midpoint = elements[pivot];
        int i = start, j = end;
    
        while (i < j) {
            while (elements[i] < midpoint) {
                i++;
            }
    
            while (elements[j] > midpoint) {
                j--;
            }
    
            if (i <= j) {
                int temp = elements[i];
                elements[i] = elements[j];
                elements[j] = temp;
                i++;
                j--;
            }
        }
        // Guessing something's wrong here
        if (k == pivot) {
            System.out.println(elements[pivot]);
            return pivot;
        } else if (k < pivot) {
            return quickSelect(elements, k, start, pivot - 1);
        } else {
            return quickSelect(elements, k, pivot + 1, end);
        }
    }
    
    private static int getPivot(int[] elements, int start, int end) {
        int pivot = start;
        int lessThan = start;
    
        for (int i = start; i <= end; i++) {
            int currentElement = elements[i];
            if (currentElement < elements[pivot]) {
                lessThan++;
                int tmp = elements[lessThan];
                elements[lessThan] = elements[i];
                elements[i] = tmp;
            }
        }
        int tmp = elements[lessThan];
        elements[lessThan] = elements[pivot];
        elements[pivot] = tmp;
    
        return lessThan;
    }
    
    private static int quickSelect(int[] elements, int k, int start, int end) {
    
        int pivot = getPivot(elements, start, end);
    
        if (k == (pivot - start + 1)) {
            System.out.println(elements[pivot]);
            return pivot;
        } else if (k < (pivot - start + 1)) {
            return quickSelect(elements, k, start, pivot - 1);
        } else {
            return quickSelect(elements, k - (pivot - start + 1), pivot + 1, end);
        }
    }