我正在尝试实现以下伪代码。我只需要使用逻辑分区来执行此操作。
Procedure SELECT( k,S)
{ if |S| =1 then return the single element in S
else { choose an element a randomly from S;
let S1,S2,and S3 be he sequences of elements in S
less than, equal to, and greater than m, respectively;
if |S1| >=k then return SELECT(k,S1)
else
if (|S1| + |S2| >=k then return m
else return SELECT(k-|S1|-|S2| , S3);
}
}
到目前为止,这是我的尝试:
public static int select(int k, int[] s, int arrayLeft, int arrayRight) {
if (s.length == 1) {
return s[0];
} else {
Random rand = new Random();
int right = rand.nextInt(arrayRight) + arrayLeft;
int m = s[right];
int pivot = partition(s, arrayLeft, right); // pivot = |s1|
if (pivot >= k) {
return select(k, s, arrayLeft, pivot - 1);
} else {
// Calculate |s2|
int s2Length = 0;
for (int i = pivot; s[i] == m; i++) {
s2Length++;
}
if (pivot + s2Length >= k) {
return m;
} else {
int s3Left = pivot + s2Length;
return select(k - pivot - s2Length, s, s3Left + 1, s.length);
}
}
}
}
// all elements smaller than m are to the left of it,
// all elements greater than m are to the right of it
private static int partition(int[] s, int left, int right) {
int m = s[right];
int i = left;
for (int j = left; j <= right - 1; j++) {
if (s[j] <= m) {
swap(s, i, j);
i++;
}
}
swap(s, i, right);
return i;
}
private static void swap(int[] s, int i, int j) {
int temp = s[i];
s[i] = s[j];
s[j] = temp;
}
我的select
方法没有返回实际的第k个最小元素。分区方法仅在小于m的元素上正常工作。在m右边的数组部分,有任何值的元素。我该如何解决?我在网上看到的所有解决方案都与我的方法相同。任何帮助表示赞赏!
答案 0 :(得分:1)
我不确定您的代码应该如何工作的详细信息,但我认为我发现了一些可疑点。
首先,我认为您应该准确了解适用于您的方法以及它如何使用arrayLeft
和arrayRight
。写一个Javadoc评论并说明这一点。这将使您和其他任何人更容易争论代码中的正确和错误。
这是错误的:
if (s.length == 1) {
您正在通过所有递归调用传递相同的数组,因此如果它从一开始就没有长度1(一个简单的情况),它将永远不会有长度1.而是使用arrayLeft
和{{ 1}}确定要考虑的元素数量。
这条线看起来不正确:
arrayRight
如果 int right = rand.nextInt(arrayRight) + arrayLeft;
为10且arrayLeft
12,则最多可以产生21.我在下一行中观察到arrayRight
一次因为ArrayIndexOutOfBoundsException
指向数组外部
此行中的注释不正确,可能会导致您对代码的错误参数:
right
int pivot = partition(s, arrayLeft, right); // pivot = |s1|
返回的pivot
是重新排序后partition()
的索引。我认为正确的陈述是m
。请检查一下。
我进一步认为你不应该将pivot == arrayLeft + |s1|
作为上述调用中的最后一个参数,而是right
。此错误可能是您arrayRight
在partition()
右侧留下任何值的观察结果。
你也可能冒m
的风险:
ArrayIndexOutOfBoundsException
您应该添加其他条件,例如 for (int i = pivot; s[i] == m; i++) {
或i <= arrayRight
。
最后,这在我看来是错误的:
i < s.length
我在想:
return select(k - pivot - s2Length, s, s3Left + 1, s.length);
但请查看您自己的知识。我特别怀疑 return select(k - pivot - s2Length, s, s3Left, arrayRight);
。