合并排序和递归混淆/代码不起作用

时间:2018-08-21 20:45:59

标签: java recursion mergesort

我已经参加了几天,阅读了许多伪代码并观看了视频以解释递归和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:只是想说我对这篇文章的惊人回答是多么的感谢,非常感谢您的宝贵时间。

2 个答案:

答案 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,然后再次四舍五入。依此类推,以此类推,直到最终n2k的结尾掉下来,我们得到一个arr

在mergesort的这一部分中,我们尝试将尚未合并到ArrayIndexOutOfBoundsException中的arr的内容复制到R中,但是我们忘记增加{{1} }。因此,要解决此循环,请增加arrj

j

请注意,上一个循环(以k开头的循环递增了 while(j<n2){ arr[k] = R[j]; j++; k++; } while(i<n1)。现在,这一更改使两个循环看起来更加相似。

那么,我们再次运行代码,会发生什么?我们仍然得到ArrayIndexOutOfBoundsException。显然我们还没有解决问题,但是如果我们遇到相同的错误,我们是否取得了任何进展?

i方法的目的是合并k的子数组,从位置mergearr,包括位置p到{{1 }} 包括的。如果对这两个子数组进行了排序,则将qq+1r的整个arr子数组合并之后。

但是,当我们将值写回到p时,我们从索引r开始。它是否正确?假设arr的长度为2,1arrp = 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方法的目的是将4mergearr进行排序。仔细查看正在将哪些值从数组复制到pr中:

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代替in2之外,这两个循环之间没有任何区别的n1中?

请注意,当您复制到R时,您是从位置L开始复制值。这些是第二个排序的子数组中的值。但是,当您复制到R时,就是从位置0开始复制值。这不一定是第一个排序的子数组开始的位置。那当然是从q+1开始的。

将这些循环中的第一个替换为:

L

最后,我们运行代码,发现我们现在有一个有效的mergesort程序。