将迭代函数转换为递归函数

时间:2011-10-29 14:29:17

标签: c++ c recursion

我知道人们通常会反过来问这个问题,但我有以下问题: 我有这个迭代函数,它计算包含数据值20的循环双链接列表中的所有节点。现在,我如何使这个递归,递归函数的基本情况(终止情况)是什么? 任何帮助表示赞赏:

int count(node *start)
{
    int c;
    c = 0;
    if(start == NULL)
        return 0;
    if((start->roll_no) == 20)
        c = 1;
    node *current = start;
    while(current->next != start)
    {
        if((current->next->roll_no) == 20){
        c++;
        }
        current = current->next;
    }

    return c;
}

5 个答案:

答案 0 :(得分:4)

我认为这应该有用(但请注意,它需要额外的参数来跟踪开始):

int count(node *start)
{
    return count_helper(start, start);
}
int count_helper(node *current, node *start)
{
    int c;
    c = 0;
    if(current == NULL)
        return 0;
    if((current->roll_no) == 20)
        c = 1;
    if(current->next == start) return c;
    return (c + count_helper(current->next, start));
}

答案 1 :(得分:1)

int count_recursive (node* current, node* start) {
  if (current == NULL)
    return 0;
  if (current->next == start)
    return (current->roll_no == 20 ? 1 : 0);
  if (current->roll_no == 20)
    return count_recursive(current->next, start) + 1;
  else
    return count_recursive(current->next, start);
}
int count(node* start) {
  return count_recursive(start, start);
}

基本情况是“列表为空”或“我们在列表的末尾”。然后你通过获取列表的其余部分(没有我们刚刚看到的项目)进行递归并完成同样的事情。

请注意,这不是尾递归(尽管它可能会被优化为尾递归选项),因此它会增加堆栈并可能会爆炸。

递归尾巴:

int count_recursive (node* current, node* start, int c) {
  if (current == NULL)
    return c;
  if (current->next == start)
    return (current->roll_no == 20 ? 1 : 0) + c;
  if (current->roll_no == 20)
    return count_recursive(current->next, start, c+1);
  else
    return count_recursive(current->next, start, c);
}
int count(node* start) {
  return count_recursive(start, start, 0);
}

尾部递归选项更有可能被编译器优化为循环,但是一个足够智能的编译器应该将它们都转换为循环。

答案 2 :(得分:1)

int count(struct node * ptr)
{
    return ptr==NULL ? 0 : (ptr->roll_no == 20 ? 1:0) + count(ptr->next);
}

更新:列表显示为圆形。

int count(struct node * start, struct node * ptr)
{
    return ptr==NULL || ptr->next == start ? 0 
                                           : (ptr->roll_no == 20 ? 1:0) 
                                             + count(start, ptr->next);
}
/* to be called like: */
cnt = count (the_list, the_list);

更新2 :(未计算最后一个节点)

int count(struct node * start, struct node * ptr)
{
    return ptr==NULL  ? 0 
                      : (ptr->roll_no == 20 ? 1:0) 
                        + ptr->next == start ? 0
                                             : count(start, ptr->next);
}

UPDATE3:确实需要一对额外的括号......

#include <stdio.h>

struct node {
        struct node *next;
        int roll_no;
        };

struct node nodes[8] =
{{ nodes+1, 20} ,{ nodes+2, 0}
,{ nodes+3, 20} ,{ nodes+4, 0}
,{ nodes+5, 20} ,{ nodes+6, 0}
,{ nodes+7, 20} ,{ nodes+0, 0}
};

unsigned count(struct node * start, struct node * ptr)
{
    return ptr==NULL
              ? 0
              : (ptr->roll_no == 20 ? 1:0)
                + (ptr->next == start
                    ? 0
                    : count(start, ptr->next)
                  )
              ;
}

#define COUNT(p) count(p,p)

int main (void)
{
unsigned cnt,idx;

for (idx = 0; idx < 8 ; idx++) {
    cnt = COUNT (nodes+idx);
    printf ("count@%u = %u\n", idx, cnt);
    }

return 0;
}

答案 3 :(得分:0)

没有使这个递归,因为结构中没有递归,它已经是一个列表。

通常,因为递归有很多开销,所以你可以通过创建'level to do'的列表(或堆栈)来重写这样的函数到迭代。您可以在堆栈上推送项目,然后循环您的例程直到堆栈为空,而不是递归调用该函数。

一个例子是列出文件树。您也可以将目录名称推送到要处理的目录堆栈上,而不是为每个找到的目录递归调用该函数。这样,当你有一个深度嵌套的树时,你没有大量的目录句柄或迭代器或你正在使用的任何东西。

但这里没有一个适用,因为你根本没有树。

可以这样做:你可以用递归调用替换while,但你必须通过原始的启动,或者使它全局,否则你不知道何时打破递归。此外,尽管可能,如果你有一长串清单,你很快就会遇到麻烦。

答案 4 :(得分:0)

这个怎么样:

int count(node *start){  
   if(!start) return 0;  
   int countValue = 0; 
   return count(start,start,&countValue);
}


int count(node *start, node *next, int *count){  
    if(start == next)//circular list so this is your base
       return *count;
    if(next->next->roll_no) == 20){  
         *count++;
    }  
    return count(start,next->next,count);  
}

虽然修改输入参数的递归函数不是自定义的。
也不使用全局变量。
这是我可以提出的第一种方法