【问题标题】:Merge Sort using recursion使用递归合并排序
【发布时间】:2017-12-22 03:11:48
【问题描述】:

我尝试实现递归合并排序,但出现堆栈溢出错误。

public class MergeSort {
    static int input[],mid;
    public static void mergeSort(int input[],int start,int end ){
        if(start>end){
            return;
        }
// dividing input array into two equal parts
        mid=(start+end)/2;
        mergeSort(input,start,mid);
        mergeSort(input,mid+1,end);
        merge(input,start,mid,end);
    }
    public static void merge(int input[],int start,int mid,int end )
    {
        int l[]=new int[mid-start+1];
        int r[]=new int[end-mid];
        for(int i=1;i<end-start+1;i++){
            l[i]=input[start+i-1];
        }
        for(int j=1;j<end-mid;j++){
            r[j]=input[mid+j];
        }

    l[end-start+2]='\u221e';// ASCII vlaue of infinity at the end of left array
    r[end-mid+1]='\u221e';//ASCII vlaue of infinity at the end of right array
    int i=1,j=1;
    for(int k=start;k<end;k++){
        if(l[i]<=r[j]){
            input[k]=l[i];
            i=i+1;
        }
        else{
            input[k]=r[j];
            j=j+1;
        }
    }

【问题讨论】:

  • 如果您了解 StackOverflow 的含义,那应该会提示您问题出在哪里。
  • 您测试的间隔有多大?你甚至有一个关于小输入的 StackOverflow 吗?如果不是,结果输出是否正确?如果它也发生在小输入上,那么您的递归策略可能会出错。尝试检查您是否在正确的索引上调用该方法,以及您的停止标准是否正确。 StackOverflow 表示您的递归不会停止或太大而无法计算(例如内存不足)。对照维基百科的伪代码检查代码,例如:en.wikipedia.org/wiki/Merge_sort
  • 调试工作的痕迹在哪里?如果不出意外,请在每个方法的顶部粘贴一个简单的 print 命令以显示输入参数。这会告诉你很多关于递归进程的信息。

标签: java sorting recursion


【解决方案1】:

问题是你的终止条件:

    if(start > end){
        return;
    }
    // dividing input array into two equal parts
    mid=(start+end)/2;
    mergeSort(input,start,mid);   //  <= infinite recursion
    mergeSort(input,mid+1,end);

在第一次递归中,没有办法将mid(下一个end 值)减少到小于start。例如,从范围 [0, 6] 开始,这是第一次递归调用的start, end 值序列:

0 6    mid = (0+6)/2 = 3
0 3    mid = (0+3)/2 = 1
0 1    mid = (0+1)/2 = 0
0 0    mid = (0+0)/2 = 0
0 0    mid = (0+0)/2 = 0
...

你永远不会达到start &gt; end 的地步。无限递归。

也许start &gt;= end 对你有用?这使您的基本案例成为一个 1 项数组,而不是一个空数组。

【讨论】:

  • 很好地解释了为什么这是无限递归(比我认为的要好),一旦获得更多选票,我会投票赞成。
【解决方案2】:

你有无限递归。仔细查看调用:

if(start>end){
        return;
    }
 // dividing input array into two equal parts
    mid=(start+end)/2;
    mergeSort(input,start,mid);
    mergeSort(input,mid+1,end);
    merge(input,start,mid,end);

您总是在第一次调用时传递相同的 start 值 - 您永远不会真正更改它 - 并且 mid 永远不会小于 start。因此,您的终止条件永远不会成立,这是无限递归。

【讨论】:

  • 我不认为这是正确的:代码确实在第二次调用中更改start,并在第一次调用中更改end。请注意,merge不是递归的。这是基本的归并排序原则:单独排序每一半;然后合并结果。
  • @Prune 但是对于第一次调用 (mergeSort(input, start, mid)),,实际上是无限的,因为start &gt; end 不可能是真的。
  • @Prune 再看一遍我可能会更清楚地表达它,我会编辑。
猜你喜欢
  • 1970-01-01
  • 2021-11-06
  • 2019-01-22
  • 1970-01-01
  • 2020-03-04
  • 2010-12-06
相关资源
最近更新 更多