为什么这个递归函数在列表中搜索一个项目,导致堆栈溢出?

时间:2014-01-09 18:48:15

标签: c++ recursion stack-overflow

我已经定义了一个基本的列表结构,一个简单的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()中的递归调用数是否会导致堆栈溢出?我怎样才能摆脱这个错误?

3 个答案:

答案 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