简体   繁体   English

合并排序导致堆栈溢出?

[英]Merge sort causing stack to overflow?

I wrote mergesort() in C++ for linked lists. 我在C ++中为链接列表编写了mergesort() The issue is that my professor has provided test code with a very large list (length of 575,000). 问题是我的教授提供的测试代码列表很大(长度为575,000)。 This causes a stack overflow error for my function since it is written recursively. 因为它是递归编写的,所以这会导致我的函数出现堆栈溢出错误。

So it's possible my professor expects us to write it using iterations instead of recursion. 因此,我的教授可能希望我们使用迭代而不是递归来编写它。 I wanted to ask if there is anything wrong with my code that may be causing the stack to overflow? 我想问一下我的代码是否有任何错误,可能导致堆栈溢出?

My code: 我的代码:

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;
    }
}

So you have three recursive functions. 因此,您具有三个递归函数。 Let's look at the maximum depth of each with the worst case of a list of 575000 elements: 让我们以575000个元素的最坏情况看一下每个元素的最大深度:

  • merge(): This looks to iterate over the entire list. merge():这看起来要遍历整个列表。 So 575000 stack frames. 因此有575000个堆栈帧。
  • split(): This looks to iterate over the entire list in pairs. split():这看起来要成对地遍历整个列表。 So ~250000 stack frames. 因此〜250000个堆栈帧。
  • mergesort(): This looks to iterate in a splitting fashion. mergesort():这看起来要以拆分的方式进行迭代。 So log_2(575000) or about 20 stack frames. 因此, log_2(575000)或大约20个堆栈帧。

So, when we run our programs, we're given a limited amount of stack space to fit all of our stack frames. 因此,当我们运行程序时,将获得有限的堆栈空间以适合所有堆栈框架。 On my computer, the default limit is about 10 megabytes. 在我的计算机上,默认限制约为10 MB。

A rough estimate would be that each of your stack frames takes up 32 bytes. 粗略估计是每个堆栈帧占用32个字节。 For the case of merge() , this means that it would take up about 18 megabytes of space, which is well beyond our limit. 对于merge() ,这意味着它将占用大约18兆字节的空间,这远远超出了我们的限制。

The mergesort() call itself though, is only 20 iterations. 不过, mergesort()本身仅进行了20次迭代。 That should fit under any reasonable limit. 这应该在任何合理的限制内。

Therefore, my takeaway is that merge() and split() should not be implemented in a recursive manner (unless that manner is tail recursive and optimizations are on). 因此,我得出的结论是, merge()split()不应以递归的方式实现(除非这种方式是尾递归且优化处于启用状态)。

A bit late, but it's the recursive merge() that is causing stack overflow. 有点晚了,但是正是递归merge()导致了堆栈溢出。 The recursive split() is not an issue, because its maximum depth is log2(n). 递归split()不是问题,因为其最大深度为log2(n)。

So only merge() needs to be converted to iteration. 因此,仅merge()需要转换为迭代。

As commented a long time ago, a bottom up approach using a small (25 to 32) array of pointers is simpler and faster, but I wasn't sure it this would be an issue with getting too much help for the assignment. 正如很久以前的评论,使用小的(25到32)指针数组的自下而上的方法更简单,更快捷,但是我不确定这对于获得太多的分配帮助会是一个问题。 Link to wiki pseudo-code: 链接至Wiki伪代码:

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

Link to working C example: 链接到工作的C示例:

http://code.geeksforgeeks.org/Mcr1Bf http://code.geeksforgeeks.org/Mcr1Bf

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

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