Java 选择秩算法
下面是选择秩算法的实现,该算法用于查找数组中第k个最小元素之前的元素。有时该程序工作正常,但有时由于堆栈溢出错误(代码段下面的错误)而失败Java 选择秩算法,java,algorithm,Java,Algorithm,下面是选择秩算法的实现,该算法用于查找数组中第k个最小元素之前的元素。有时该程序工作正常,但有时由于堆栈溢出错误(代码段下面的错误)而失败 公共静态整数兰德(整数左,整数右){ 返回left+(int)(Math.random()*(double)(right-left)); } 公共静态int-rank(int[]数组,int-left,int-right,int-rank){ int pivot=rand(左、右); int leftend=partition(数组,左,右,数组[pivot
公共静态整数兰德(整数左,整数右){
返回left+(int)(Math.random()*(double)(right-left));
}
公共静态int-rank(int[]数组,int-left,int-right,int-rank){
int pivot=rand(左、右);
int leftend=partition(数组,左,右,数组[pivot]);
int size=leftend-left+1;
如果(大小==排名+1){
for(int i=0;i秩)
返回秩(数组、左、左端、秩);
else返回秩(数组,左端+1,右,秩-大小);
}
公共静态int分区(int[]数组、int左、int右、int轴){
while(true){
while(左枢轴)
对--;
如果(左>右)
返回左-1;
int temp=数组[左];
数组[左]=数组[右];
数组[右]=温度;
}
}
错误:
Exception in thread "main" java.lang.StackOverflowError
at java.util.Random.nextDouble(Random.java:409)
at java.lang.Math.random(Math.java:712)
at mod.rand(mod.java:12)
at mod.rank(mod.java:16)
at mod.rank(mod.java:25)
我想可能是rand()导致了这个问题,但我不确定。我也不知道如何解决它。递归永远不会结束,不是因为输入,而是因为使用了random, 从理论上讲,random每次都可以给你相同的数字。 例如,更改为:
public static int rand(int left, int right)
{
return right - 1;
}
在输入时尝试:
int[] array= {1,2,11,67,35};
rank(array, 0, 4, 2);
在这个输入中,您将得到
java.lang.StackOverflowerError
,因为递归永远不会结束。StackOverflower的Javadoc说:
由于应用程序递归太深而发生堆栈溢出时引发
由于默认限制非常高,StackOverflowerError通常表示无限递归
要有效诊断此类错误,请使用具有调试支持的体面IDE,为StackOverflowerError
设置异常断点,运行程序,并在达到断点后检查堆栈中的局部变量
在这里,我们得到以下堆栈:
Random.nextDouble() line: 444 [local variables unavailable]
Math.random() line: 716
Test.rand(int, int) line: 5
Test.rank(int[], int, int, int) line: 9
Test.rank(int[], int, int, int) line: 18
Test.rank(int[], int, int, int) line: 18
Test.rank(int[], int, int, int) line: 18
Test.rank(int[], int, int, int) line: 18
Test.rank(int[], int, int, int) line: 18
Test.rank(int[], int, int, int) line: 18
Test.rank(int[], int, int, int) line: 18
Test.rank(int[], int, int, int) line: 18
Test.rank(int[], int, int, int) line: 18
Test.rank(int[], int, int, int) line: 18
Test.rank(int[], int, int, int) line: 18
Test.rank(int[], int, int, int) line: 18
Test.rank(int[], int, int, int) line: 18
...
rank似乎从第18行无限调用自己。让我们通过检查局部变量来验证这一点。对于第18行的最顶层堆栈帧:
left 97
right 107
rank 5
pivot 102
leftend 107
size 11
对于下面的一个:
left 97
right 107
rank 5
pivot 101
leftend 107
size 11
下面的那个
left 97
right 107
rank 5
pivot 105
leftend 107
size 11
事实上,left
和right
在这些堆栈帧中是相同的,即算法停止了进展。我们还看到,即使每次选择不同的轴索引,leftend
仍然等于right
查看有问题的数组索引,我们可以看到:
[97] 10
[98] 10
[99] 10
[100] 10
[101] 10
[102] 10
[103] 10
[104] 10
[105] 10
[106] 10
[107] 10
看起来您没有处理子范围中所有元素正确相等的特殊情况
实际上,在这种情况下,partition
将始终返回right
,而rank
将使用相同的参数调用自身,无限递归
带回家的信息:
我假设您希望您的
rand
方法返回一个介于左(包括)和右(包括)之间的数字。但是,Math.random()方法返回一个介于0.0(包括)和1.0(排除)之间的数字。因此,在正在计算的子数组的大小为2的情况下,(即:左=4,右=5),因此,rand
函数只能返回4。
尝试在rand
函数中更改此行,以确保它可以包含上限:
返回left+(int)(Math.random()*(double)(right-left));
为了
返回left+(int)(Math.random()*(double)(right-left+1));
不,可能是秩(
这就是问题所在。可能你的递归永远不会ends@Kostia你的意思是肯定的,你能给出一个它失败的例子吗,这将使它更容易修复,而不是找到我们自己的例子调用System.out.println(“left=“+left+”\tright=“+right+”\tleftend=“+leftend”)
紧跟在int leftend=…;
之后,这样你就可以看到递归调用中的模式,也许可以确定不应该递归的地方,或者递归到过大的子范围的地方t无限递归,通常问题是您在输入到例程的同一子数组上递归调用了例程,或者您没有正确处理子数组长度为零的情况。为什么为4而不是左?4甚至不能保证为[left,right]…对于真实随机数,发生这种情况的概率(即使只有两种选择是可能的)是导致堆栈溢出所需的数千次。这种概率非常接近于零,更可能是宇宙射线在计算机内存中翻转了一点导致失败(是的,random
只是一个伪随机生成器,但是它的分布非常均匀。它不会一直返回相同的数字)。问题是我没有处理子数组中只有两个元素的情况,不像你说的那样。