Java 在未排序数组中查找第k个最小元素
我正在尝试实现以下伪代码。我只需要使用逻辑分区就可以了Java 在未排序数组中查找第k个最小元素,java,sorting,partitioning,pseudocode,Java,Sorting,Partitioning,Pseudocode,我正在尝试实现以下伪代码。我只需要使用逻辑分区就可以了 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 gre
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;
}
public static int select(int k,int[]s,int arrayLeft,int arrayRight){
如果(s.length==1){
返回s[0];
}否则{
Random rand=新的Random();
int right=rand.nextInt(arrayRight)+arrayLeft;
int m=s[右];
int pivot=分区(s,arrayLeft,right);//pivot=| s1|
如果(枢轴>=k){
返回选择(k、s、arrayLeft、pivot-1);
}否则{
//计算| s2|
int s2Length=0;
对于(int i=pivot;s[i]==m;i++){
s2Length++;
}
如果(枢轴+s2Length>=k){
返回m;
}否则{
int s3Left=枢轴+s2Length;
返回选择(k-轴-s2Length,s,s3Left+1,s.length);
}
}
}
}
//所有小于m的元素都位于其左侧,
//大于m的所有元素都位于其右侧
私有静态int分区(int[]s,int左,int右){
int m=s[右];
int i=左;
对于(int j=left;j我不确定代码应该如何工作的细节,但我想我已经发现了一些可疑点
首先,我认为您应该准确地说明方法的有效参数,以及它如何使用arrayLeft
和arrayRight
。写一条Javadoc注释并说明这一点。这将使您和其他人更容易就代码中的正确和错误进行争论
这是错误的:
if (s.length == 1) {
您通过所有递归调用传递相同的数组,因此如果从一开始它就没有长度1(一个小事一桩),它就永远不会有长度1。而是使用<代码> ARARY-Leave和ArayLeale>代码>来确定要考虑的元素的数量。
这一行看起来不对:
int right = rand.nextInt(arrayRight) + arrayLeft;
如果arrayLeft
为10,而arrayRight
12,则可能最多产生21。我曾在下一行观察到ArrayIndexOutOfBoundsException
,因为right
指向数组外部
这一行中的注释不正确,可能导致有关代码的错误参数:
int pivot = partition(s, arrayLeft, right); // pivot = |s1|
从partition()
返回的pivot
是重新排序后m
的索引。我认为正确的语句是pivot==arrayLeft+|s1
。请检查您自己
我进一步认为,您不应将right
作为上述调用中的最后一个参数传递,而应传递arrayRight
。此错误可能是您观察到partition()
将任何值保留在m
右侧的原因
您可能会在以下情况下出现ArrayIndexOutOfBoundsException
:
for (int i = pivot; s[i] == m; i++) {
你应该添加一个额外的条件,比如i i i'm Middle.在伪代码中,它在哪里说了关于重新排序数组的内容?因为如果你无论如何都要重新排序,你可以使用排序算法,然后返回数组的第k个元素…该算法应该比完全排序更快。你必须重新排序以某种方式呈现S1、S2和S3,通过对数组进行重新排序并不是最愚蠢的事情。您需要学习使用调试器。select
是否应该通过arraylight
选择数组索引中的第k个最小元素arrayLeft
包含?独占?很抱歉,我应该更清楚这一点。当用户首先调用该方法,arrayLeft为0,arrayRight是数组中的最后一个元素。我应该创建另一个方法来调用select
,这样用户只需要指定k和数组。
return select(k - pivot - s2Length, s, s3Left + 1, s.length);
return select(k - pivot - s2Length, s, s3Left, arrayRight);