繁体   English   中英

合并排序导致堆栈溢出?

[英]Merge sort causing stack to overflow?

我在C ++中为链接列表编写了mergesort() 问题是我的教授提供的测试代码列表很大(长度为575,000)。 因为它是递归编写的,所以这会导致我的函数出现堆栈溢出错误。

因此,我的教授可能希望我们使用迭代而不是递归来编写它。 我想问一下我的代码是否有任何错误,可能导致堆栈溢出?

我的代码:

typedef struct listnode {
    struct listnode * next;
    long value; 
} LNode;

LNode* mergesort(LNode* data) {
    if(data == NULL || data->next == NULL) {
        return data;
    }else {
        LNode* s = split(data);

        LNode* firstSortedHalf = mergesort(data);
        LNode* secondSortedHalf = mergesort(s);

        LNode* r = merge(firstSortedHalf, secondSortedHalf);
        return r;
    }
}

LNode* split(LNode* list) {
    if(list) {
        LNode* out = list->next;

        if(out) {
            list->next = out->next;
            out->next = split(out->next);
        }
        return out;
    }else {
        return NULL;
    }
}

LNode* merge(LNode* a, LNode* b) {
    if(a == NULL)
        return b;
    else if(b == NULL)
        return a;

    if(a->value < b->value) {
        a->next = merge(a->next,b);
        return a;
    }else {
        b->next = merge(a, b->next);
        return b;
    }
}

因此,您具有三个递归函数。 让我们以575000个元素的最坏情况看一下每个元素的最大深度:

  • merge():这看起来要遍历整个列表。 因此有575000个堆栈帧。
  • split():这看起来要成对地遍历整个列表。 因此〜250000个堆栈帧。
  • mergesort():这看起来要以拆分的方式进行迭代。 因此, log_2(575000)或大约20个堆栈帧。

因此,当我们运行程序时,将获得有限的堆栈空间以适合所有堆栈框架。 在我的计算机上,默认限制约为10 MB。

粗略估计是每个堆栈帧占用32个字节。 对于merge() ,这意味着它将占用大约18兆字节的空间,这远远超出了我们的限制。

不过, mergesort()本身仅进行了20次迭代。 这应该在任何合理的限制内。

因此,我得出的结论是, merge()split()不应以递归的方式实现(除非这种方式是尾递归且优化处于启用状态)。

有点晚了,但是正是递归merge()导致了堆栈溢出。 递归split()不是问题,因为其最大深度为log2(n)。

因此,仅merge()需要转换为迭代。

正如很久以前的评论,使用小的(25到32)指针数组的自下而上的方法更简单,更快捷,但是我不确定这对于获得太多的分配帮助会是一个问题。 链接至Wiki伪代码:

http://en.wikipedia.org/wiki/Merge_sort#Bottom-up_implementation_using_lists

链接到工作的C示例:

http://code.geeksforgeeks.org/Mcr1Bf

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM