Java Quickselect实现不起作用
我试图编写代码来确定数组中最小的n个项。很遗憾,我正在为此挣扎。根据我当年大学课本上的算法,这看起来是正确的。然而,很明显我做错了什么,因为它给了我一个堆栈溢出异常 我的做法是:Java Quickselect实现不起作用,java,algorithm,quicksort,quickselect,Java,Algorithm,Quicksort,Quickselect,我试图编写代码来确定数组中最小的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这无法解决问题,但您的代码有几个问题:
- 如果您不检查i
start,在某些情况下可能会跑出边界
<>你选择你的支点在子数组的中间,但是没有任何证据证明它在分区过程中不会改变位置。然后,用旧的枢轴位置检查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);
}
}