关于递归:合并排序Java实现错误

 2020-06-30 

Merge Sort java implementation error

好的,所以我试图在Java中实现合并排序,但是在数组拆分时遇到了以下错误:

1
2
3
4
5
6
7
8
Exception in thread"main" java.lang.IllegalArgumentException: 2 > 1
    at java.util.Arrays.copyOfRange(Arrays.java:3591)
    at MergeSortS.recMergeSort(MergeSortS.java:26)
    at MergeSortS.recMergeSort(MergeSortS.java:28)
    at MergeSortS.mergeSort(MergeSortS.java:17)
    at MergeSortM.main(MergeSortM.java:16)
Java Result: 1
BUILD SUCCESSFUL (total time: 1 second)

我的代码段如下,请帮助我在此处确定我的问题... :(
我特意在最后注释掉了recMergeSort(right)递归调用,因为我想更正recMergeSort(left)调用...

1
2
3
4
5
6
7
8
9
10
11
12
public void recMergeSort(int[] tempArray){
        if(tempArray.length>1){
            int mid=(tempArray.length)/2;

            int[] left=Arrays.copyOfRange(tempArray,0,mid);

            int[] right=Arrays.copyOfRange(tempArray,mid+1,tempArray.length-1);

            recMergeSort(left);
            //recMergeSort(array, right, mid+1, right.length-1);
        }
    }

编辑
好的,所以我检查了另一个站点和copyOfRange方法上的javadoc,要求满足以下条件:

1
2
3
4
Parameters:
original - the array from which a range is to be copied
from - the initial index of the range to be copied, **inclusive**
to - the final index of the range to be copied, **exclusive**. (This index may lie outside the array.)

修复后,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
public void recMergeSort(int[] tempArray){
        if(tempArray.length>1){
            int mid=(tempArray.length)/2;

            int[] left=Arrays.copyOfRange(tempArray,0,mid+1);

            int[] right=Arrays.copyOfRange(tempArray,mid+1,tempArray.length);

            recMergeSort(left);
            //recMergeSort(array, right, mid+1, right.length-1);
        }
    }

我收到以下错误:

1
Exception in thread"main" java.lang.StackOverflowError

请帮助我纠正此问题... :(


出现java.lang.StackOverflowError的原因是,您的左数组将永远不会成为大小为1的数组。如果进入if块,则意味着中位数最小值为1,因为tempArray可以满足2。然后,当您向左复制2到0时,您再次向左复制所有元素,而右边为空


看来您被Arrays.copyOfRange()方法所困扰。请尝试以下代码:

1
2
3
4
5
6
7
8
9
10
public void recMergeSort(int[] tempArray){
    if (tempArray.length > 1 ){
        int mid=(tempArray.length)/2;                                       // mid = 2
        int[] left = Arrays.copyOfRange(tempArray, 0, mid);                 // [10, 20]
        int[] right = Arrays.copyOfRange(tempArray, mid, tempArray.length); // [30, 40, 50]

        recMergeSort(left);
        //recMergeSort(array, right, mid+1, right.length-1);
    }
}

Arrays.copyOfRange(array, lowIndex, highIndex)将复制从lowIndex包含和highIndex包含的访问。这意味着左副本的highIndex应该与右副本的lowIndex相同。

用法:

1
2
int[] tempArray = new int[] {10, 20, 30, 40, 50};
recMergeSory(tempArray);


我认为递归太多。来自Java文档。

Thrown when a stack overflow occurs because an application recurses
too deeply.

顺便说一句:查看tempArray.length等于2时会发生什么。

我认为您的代码有错误。

1
2
3
4
5
int mid=(tempArray.length)/2; //mid equals 1
//calls with params tempArray, 0, 2
int[] left=Arrays.copyOfRange(tempArray,0,mid+1);
//calls with params tempArray, 2, 2
int[] right=Arrays.copyOfRange(tempArray,mid+1,tempArray.length);

最后一行是问题。长度为2,第二个参数为2,第三个参数为2。返回数组的长度为0。


在考虑了您指出的所有错误之后,我通过更改以下内容以及在OP上进行编辑来使其正常工作:

1
int mid=(tempArray.length-1)/2;

谢谢大家的支持。我浪费了整整一天的时间试图弄清楚这个烂摊子!


堆栈溢出是一个与以下事实有关的问题:对于recMergeSort的每次调用,您都在创建两个新数组。这称为log(n)次,并使堆栈变满。

要解决此问题,您可以增加堆栈大小(请参阅:java调用堆栈的最大深度是多少?),也可以通过将recMergeSort(int[] tempArray)的参数更改为recMergeSort(int[] unSortedArray, int startIndex, int endIndex)来重构代码以进行就地排序。

为了清楚起见:首先调用它是recMergeSort(array, 0, array.length-1),然后调用recMergeSort(array, startIndex, endIndex/2)recMergeSort(array, (endIndex/2)+1, endIndex)