我已经定义了一个基本的列表结构,一个简单的insert
函数和一个search
函数。代码如下:
////////////////////////////////////////////////
typedef struct list
{
int item;
struct list *next;
}List;
////////////////////////////////////////////////
List * search_list(List * l, int i)
{
if(NULL == l)
return(NULL);
if(i == l->item)
return l;
else
return search_list(l->next, i);
}
////////////////////////////////////////////////
void insert_list(List ** l, int i)
{
List * p = new List();
p->item = i;
p->next = *l;
*l = p;
}
我测试它的主要循环,如下所示:
int main(int, char* argv[])
{
List * mylist = new List();
for(int i = 0; i < 8000; i++)
{
insert_list(&mylist,i);
}
int val = 2000;
List * s = search_list(mylist, val);
return 0;
}
当val
为4000时,程序完成正常。但是当val
为2000时,即列表中的2000个索引,Visual Studio将以堆栈溢出终止。
search_list()
中的递归调用数是否会导致堆栈溢出?我怎样才能摆脱这个错误?
答案 0 :(得分:3)
只有在严格限制深度或算法不超过O(logN)复杂度时才应使用递归算法。如果情况并非如此,则总是冒险堆栈溢出。你的不符合复杂性要求,它是O(N)。
使用默认的Debug构建设置运行程序时,Visual Studio并不能完全帮助避免崩溃。首先,未启用尾递归优化,这需要Release构建设置,以便打开优化器。另一方面,Edit + Continue功能为一个函数分配了一堆额外的堆栈空间。如果在调试时向函数添加局部变量,则可以使用它。
您可以轻松将其关闭。 Project + Properties,C / C ++,General,将Debug Information Format设置更改为“Program Database(/ Zi)”。您的程序将不再崩溃。
答案 1 :(得分:1)
您的编译器应该告诉您一件事:search_list的这种递归调用不会返回任何内容。你没有收到关于这个的警告吗?在这里使用递归确实是个坏主意,最好用某种循环替换它。当然,一个原因是过多的堆栈使用,另一个原因是调试糟透了这种递归。
答案 2 :(得分:0)
除了堆栈溢出错误,您应该检查以下内容。您没有初始化List
处的第一个已分配的main()
实例的值,由mylist
指向。
List * mylist = new List();
您当前的代码所执行的操作是在第一次调用时传递“空”List
实例,该实例可能具有无效的next
值。这将是链接列表中的最后一个List
实例。
你应该这样做:
List * mylist = NULL;
这将确保您列表中的List
个实例的next
值为NULL
。