我已经参加了几天,阅读了许多伪代码并观看了视频以解释递归和mergesort。我理解mergesort并有点理解递归-除非它适用于数组,如下面的代码所示。我进行了一些调试,无论出界错误如何,我的程序似乎都无法正确排序。我很失落,希望您能提供任何帮助!
问题: 1)对数组进行递归意味着什么?它会创建一个由原始数组保存的子数组吗? -如果有道理。 2)为什么我遵循了t的教程,并且每次通过后都设置了k值,为什么我的代码仍会出现超出范围的错误。具体来说就是遇到这个问题。
代码如下:
public class Merge {
public static void main(String[] args) {
}
static void mergeSort(int arr[]){
int r = arr.length - 1;
Merge.sort(arr,0,r);
System.out.println(arr);
}
static void sort(int arr[], int p, int r){
if(p<r){
int q = (p+r)/2;
sort(arr,p,q);
sort(arr,q+1,r);
merge(arr,p,q,r);
}
}
static void merge(int arr[], int p, int q, int r){
int n1 = q-p+1;
int n2 = r-q;
int L[] = new int[n1];
int R[] = new int[n2];
for(int i = 0; i< n1; i++){
L[i] = arr[i];
}
for(int j = 0; j< n2; j++){
R[j] = arr[q+1+j];
}
int i = 0, j = 0;
int k = 1;
while(i<n1 && j<n2){
if(L[i]<= R[j]){
arr[k] = L[i];
i++;
}
else{
arr[k] = R[j];
j++;
}
k++;
}
while(i<n1){
arr[k] = L[i];
i++;
k++;
}
Error occurs here --> while(j<n2){
arr[k] = R[j];
k++;
}
}
}
谢谢您的帮助!
edit:只是想说我对这篇文章的惊人回答是多么的感谢,非常感谢您的宝贵时间。
答案 0 :(得分:0)
让我们细分您的问题-具体来说,递归是什么意思?您可以将其视为一个循环-它对自身执行操作直到达到停止条件。以一个for循环为例
for(int i = 0; i < 2; i++)
将执行该操作,直到达到变量i不小于2的情况为止。同样,递归
void methodLoop(int input){
int i = input;
if(i < 2){
methodLoop(i+1);
}
else{
System.out.println("Base case reached! I is no longer less than 2!");
}
}
执行类似的操作,只是使用递归!
这对数组意味着什么?这取决于。您所涉及的问题是一个称为多维数组的概念-数组中的数组。它们就像普通数组一样工作,只是一个数组,在每个索引中都包含另一个数组-实例化如下
String[][] multidimensionalarray = new array[4][4]
为使这种概念形象化,可能更容易将其视为坐标网格,其中索引是坐标位置,并且该索引处的值包含有关该位置的信息。例如,假设多维数组已被这样的数据填充,则可能看起来像这样:
4 a b c d
3 e f g h
2 i j k l
1 m n o p
1 2 3 4
,然后multidimensionarray [2] [3]的值将返回字符串k!
答案 1 :(得分:0)
说实话,我认为您的句子“数组递归”没有任何意义。
您的代码具有一个数组arr
,该数组将被排序。您的merge
方法应该对该数组的各个部分进行排序,但是每次调用它时,它都具有相同的整个数组对象。没有子数组;这取决于该方法来对一个数组的相关部分进行排序。如果此方法没有执行应有的功能,则会出现问题。
让我们仔细看看出现错误的循环:
while(j<n2){
arr[k] = R[j];
k++;
}
假设我们使用j < n2
进入此循环。会发生什么?
因为j < n2
进入循环,所以我们将R[j]
复制到arr[k]
,然后递增k
。我们回到循环的顶部,发现j
仍然小于n2
,因为两个变量都没有改变,因此我们将R[j]
复制到arr[k]
并递增{{ 1}}。我们回到循环的顶部,发现k
仍然小于j
,然后再次四舍五入。依此类推,以此类推,直到最终n2
从k
的结尾掉下来,我们得到一个arr
。
在mergesort的这一部分中,我们尝试将尚未合并到ArrayIndexOutOfBoundsException
中的arr
的内容复制到R
中,但是我们忘记增加{{1} }。因此,要解决此循环,请增加arr
和j
:
j
请注意,上一个循环(以k
开头的循环递增了 while(j<n2){
arr[k] = R[j];
j++;
k++;
}
和while(i<n1)
。现在,这一更改使两个循环看起来更加相似。
那么,我们再次运行代码,会发生什么?我们仍然得到ArrayIndexOutOfBoundsException。显然我们还没有解决问题,但是如果我们遇到相同的错误,我们是否取得了任何进展?
i
方法的目的是合并k
的子数组,从位置merge
到arr
,包括位置p
到{{1 }} 包括的。如果对这两个子数组进行了排序,则将q
从q+1
到r
的整个arr
子数组合并之后。
但是,当我们将值写回到p
时,我们从索引r
开始。它是否正确?假设arr
的长度为2,1
,arr
和p = 0
。我们有两个要排序的元素。第一个写入哪里,第二个写入哪里?
答案是第一个写入q = 0
,并且您的代码引发异常,因为它试图将第二个写入r = 1
,但不存在。
您希望arr[1]
从要排序的子数组的开头开始。您希望arr[2]
从k
开始。
所以替换行
k
使用
p
我们再试一次,现在我们发现代码不再引发异常,而是打印诸如 int k = 1;
之类的难以理解的内容。烦人的是,这是Java默认情况下如何打印数组的方式。要解决此问题,请将行 int k = p;
添加到文件中,并替换行
[I@65fb1cd
使用
import java.util.Arrays;
您的代码现在应该在运行时打印出一个数字列表。
但是,我们现在看到我们的代码没有正确地对数组进行排序。我要求它对值 System.out.println(arr);
进行排序,然后返回 System.out.println(Arrays.toString(arr));
。 8, 1, 4, 9
已被复制,1, 1, 8, 9
已消失。
再次回想一下1
方法的目的是将4
从merge
到arr
进行排序。仔细查看正在将哪些值从数组复制到p
和r
中:
L
请注意,除了使用R
代替 for(int i = 0; i< n1; i++){
L[i] = arr[i];
}
for(int j = 0; j< n2; j++){
R[j] = arr[q+1+j];
}
,j
代替i
和n2
之外,这两个循环之间没有任何区别的n1
中?
请注意,当您复制到R
时,您是从位置L
开始复制值。这些是第二个排序的子数组中的值。但是,当您复制到R
时,就是从位置0开始复制值。这不一定是第一个排序的子数组开始的位置。那当然是从q+1
开始的。
将这些循环中的第一个替换为:
L
最后,我们运行代码,发现我们现在有一个有效的mergesort程序。