【问题标题】:Implementing Merge Sort with Java用Java实现归并排序
【发布时间】:2020-01-19 01:57:01
【问题描述】:

我试图使用 java 实现归并排序,但它说:

Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 3
    at HelloWorld.merge(HelloWorld.java:42)
    at HelloWorld.sort(HelloWorld.java:30)
    at HelloWorld.sort(HelloWorld.java:28)
    at HelloWorld.sort(HelloWorld.java:29)
    at HelloWorld.sort(HelloWorld.java:28)
    at HelloWorld.main(HelloWorld.java:10)

所以我试图在合并子例程中将原始数组复制到辅助数组中,我认为这是我用于辅助数组的长度搞砸了一切,不是“r-l+1”辅助数组的长度?

如果我将 100 作为辅助数组的长度,代码会起作用,但显然当原始数组的大小变大时它不会起作用。

请提前帮助和感谢。

public class HelloWorld{

     public static void main(String []args){

         HelloWorld ms = new HelloWorld();
         int arr[] = new int[]{4,3,0,1,3,2,4,20,13,22,10};

         ms.sort(arr, 0, arr.length - 1);

         ms.printArr(arr);

     }

     void printArr(int arr[])
     {
         int n = arr.length;
         for(int i = 0; i<n; i++){
             System.out.print(" "+arr[i]);
         }
     }

     void sort(int arr[], int l, int r)
     {
         if(l<r){
             int m = (l+r)/2;
             sort(arr, l, m);
             sort(arr, m+1, r);
             merge(arr, l, m, r);

         }

     }

     void merge(int arr[], int l, int m, int r)
     {
        //find out helper array length
        int helper[] = new int[r-l+1];
         // Your code here
         for(int i=l; i<=r; i++){
             helper[i] = arr[i];
         }
         int i = l;
         int k = l;
         int j = m+1;
         while(i<=m && j<=r){
             if(helper[i]<=helper[j]){
                 arr[k]=helper[i];
                 i++;
             }else{
                 arr[k]=helper[j];
                 j++;
             }
             k++;
         }

         while(i<=m){
             arr[k]=helper[i];
             i++;
             k++;
         }
     }


}

【问题讨论】:

    标签: java algorithm mergesort


    【解决方案1】:

    如果我理解您尝试为合并排序算法正确实现 MERGE 子例程的方式,则您正在复制数组的相关部分(来自索引 l,包括在内,将l(含)索引到辅助数组中,然后使用复制到辅助数组中的数据修改原始数组。

    在这种情况下,辅助数组确实应该有长度r-l+1。但是,查看将原始数组部分复制到辅助数组中的代码,您不会在 for 循环中偏移索引。正确的做法是:

    int helper[] = new int[r-l+1];
    
    for (int i = l; i <= r; i++){
        helper[i-l] = arr[i];
    }
    

    不要忘记数组是零索引的!

    但是,如果您绝对必须复制数组,我建议您继续使用更现代的复制数组的方法。在这种情况下,我认为最适合的是系统调用System.arraycopy(arr, l, helper, 0, r-l+1)。如果您想了解更多关于在 Java 中复制数组(完全或部分)的不同方法,请查看this answer out。

    【讨论】:

    • 你说得对,他可以这样复制: System.arraycopy(arr, l, helper, 0, helper.length);他还需要在方法末尾的while循环中访问正确的索引
    【解决方案2】:

    你创建一个大小为r - l + 1的数组

    int helper[] = new int[r-l+1];
    

    merge 方法将使用l = 3, m = 3, r = 4 执行 所以数组助手的大小为r - l + 1 = 2 = [0, 0]

    你的 for 循环从 l..r 运行

         for(int i=l; i<=r; i++){
             helper[i] = arr[i];
         }
    

    您尝试将值从arr[3] 设置为helper[3],这是不可能的,因为helper.length = 2

    这就是发生 ArrayIndexOutOfBoundsException 的原因!您可以将助手索引的访问权限修改为i - l

    void merge(int arr[], int l, int m, int r) {
        // find out helper array length
        int helper[] = new int[r - l + 1];
        // Your code here
        System.arraycopy(arr, l, helper, 0, helper.length);
        int i = l;
        int k = l;
        int j = m + 1;
        while (i <= m && j <= r) {
            if (helper[i - l] <= helper[j - l]) { // <---
                arr[k] = helper[i - l]; // <---
                i++;
            } else {
                arr[k] = helper[j - l]; // <---
                j++;
            }
            k++;
        }
    
        while (i <= m) {
            arr[k] = helper[i - l]; // <---
            i++;
            k++;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2016-09-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多