[英]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个元素的最坏情况看一下每个元素的最大深度:
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示例:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.