Recursive function convert to Non-Recursive function

来源:互联网 发布:软件怎开发的 编辑:程序博客网 时间:2024/04/30 04:07
题目:

把这个函数f(m, n) = f(m-1, f(m, n-1))转为非递归函数。

int funcRecur(int m, int n) {      if (!m || !n) {          return m + n + 1;      }      return funcRecur(m - 1, funcRecur(m, n - 1));  } 


非递归

int funcLoop(int m, int n){   stack<int> stack;   int value = 0;   while (true) {   if (!m || !n) {   value = m + n + 1;   if (!stack.size())  return value;   n = value;   m = stack.top();   stack.pop();   continue;   }   stack.push(m-1);   --n;   }  } 

 

这里有一个建设性的规则 

(i)    At the beginning of the function, code is inserted which declares a stack (called recursion stack) and initializes it to be empty. In the most general case, the stack will be used to hold the values of parameters, local variables, and a return address for each recursive call. We might prefer to use a separate stack for each value.
(ii)    Thelabel 1 is attached to the first executable statement.
(iii)    If this is a value returning function, then replace all appearances of the function name on the left hand side of assignment statements by a new variable, say z, of the same type as the function.

Now, each recursive call is replaced by a set of instructions which do the following:

(iv)   Store the values of all pass by value parameters and local variables in the stack. The pointer to the top of the stack can be treated as global.
(v)    Create the i-th new label, i, and 'store i in the stack. The value i of this label will beused as the returnaddress. This label is placed in the program as described in rule (vii).
(vi)   Evaluate the arguments of this call that correspond to pass by value parameters (they may be expressions) and assign these values to the appropriate formal parameters.
(vii)  Insert an unconditional branch to the beginning of the function.
(viii) If this is a void function, add the label created in (v) to the statement immediately following the unconditional branch. In case this statement already has a label, change it and all references to it to the label created in (v). If this is a value returning function then follow the unconditional branch by code to use the value of the variable z in the same way the function value was used earlier. The first statement of this code is given the label that was created in (v).

These steps are sufficient to remove all recursive calls from the procedure or function. Finally, we need to precede the last end statement of the function by code to do the following:

(ix)    If the recursion stack is empty, then assign the value of z to the function name and execute a normal end of function in case this is a value returning function. In the case' of a void function, we simply execute a normal end of function.
(x)    If the stack is not empty, then restore the value of all pass by value parameters and of all local variables. These are at the top of' the stack. Use the return label from the top of the stack and execute a branch to this label. This can be done using a case statement.
(xi)    In addition, the label (if any) attached to the end of procedure or function statement is moved to the first statement of the code for (ix) and, (x).

上述的算法看上去就有点头大,我们现在从简单的入手。总体来说,将递归算法转换为非递归算法有两种方法,一种是直接求值,不需要回溯;另一种是不能直接求值,需要回溯。前者使用一些变量保存中间结果,称为直接转换法;后者使用栈保存中间结果,称为间接转换法,下面分别讨论这两种方法。
1. 直接转换法
  直接转换法通常用来消除尾递归和单向递归,将递归结构用循环结构来替代。
  尾递归是指在递归算法中,递归调用语句只有一个,而且是处在算法的最后。例如求阶乘的递归算法:

  long fact(int n)   {        if (n==0) return 1;        else return n*fact(n-1);   } 

         当递归调用返回时,是返回到上一层递归调用的下一条语句,而这个返回位置正好是算法的结束处,所以
,不必利用栈来保存返回信息。对于尾递归形式的递归算法,可以利用循环结构来替代。例如求阶乘的递归算法
可以写成如下循环结构的非递归算法:

  long fact(int n)   {        int s=0;        for (int i=1; i <n; i++)           s=s*i; //用s保存中间结果        return s;   } 

       单向递归是指递归算法中虽然有多处递归调用语句,但各递归调用语句的参数之间没有关系,并且这些递归
调用语句都处在递归算法的最后。显然,尾递归是单向递归的特例。例如求斐波那契数列的递归算法如下:

  int f(int n)   {         if (n= =1 | | n= =0) return 1;         else return f(n-1)+f(n-2);   } 

  对于单向递归,可以设置一些变量保存中间结构,将递归结构用循环结构来替代。例如求斐波那契数列的算法中用s1和s2保存中间的计算结果,非递归函数如下:

  int f(int n)   {         int i, s;         int s1=1, s2=1;         for (i=3; i<n; i++) {               s=s1+s2;               s2=s1; // 保存f(n-2)的值               s1=s; //保存f(n-1)的值         }         return s;   } 

 
2. 间接转换法
  该方法使用栈保存中间结果,一般需根据递归函数在执行过程中栈的变化得到。其一般过程如下:

void NonRecursiveFunction(DATATYPE Data)
{
    while ( ExistHandyWork() || ExistSavedWork() )
    {
        while ( ExistHandyWork() )
        {
            Process(Work, Status)  // Probably push work onto stack
            NewHandyWork();
        }
        if ( ExistSavedWork() )
        {
            Pop(Work, Status);
            Process(Work, Status);  // Probably generate new handy work
        }
    }
}

 由此,对于树的前序,中序,后序遍历的non-recursive的实现如下

typedef struct tNode{            int item;            tNode* left;            tNode* right;}tNode;void preorder_traverse(tNode* head, void (*visit)(tNode*)){            stack<tNode*> tree_stack;            tree_stack.push(head);            while ( !tree_stack.empty() )            {                      visit(tree_stack.top());                        tree_stack.pop();                       if (head->right != NULL)                                   tree_stack.push(head->right);                        if (head->left != NULL)                                    tree_stack.push(head->left);           }}void inorder_traverse(tNode* head, void (*visit)(tNode*)){            stack<tNode*> tree_stack;            tNode* pNode = head;            while (!tree_stack.empty() || pNode != NULL)            {                        while (pNode)                        {                                    tree_stack.push(pNode);                                   pNode = pNode->left;                        }                        pNode = tree_stack.top();                        visit(pNode);                        tree_stack.pop();                        pNode = pNode->right;             }}void postorder_traverse(tNode* head, void (*visit)(tNode*)){           stack<tNode*> tree_stack;           tNode* pNode = head;            tNode* preNode = NULL;            while (!tree_stack.empty() || pNode != NULL)           {                        while (pNode)                        {                                    tree_stack.push(pNode);                                    pNode = pNode->left;                       }                         pNode = tree_stack.top();                        if (pNode->right == NULL || preNode == pNode->right)                        {                                    preNode = tree_stack.top();                                    visit(preNode);                                    tree_stack.pop();                                    pNode = NULL; /*为了继续检查stack内的元素,而不是向左走*/                        }                        else                                    pNode = pNode->right;            }}


 

参考文献

http://www.cmpe.boun.edu.tr/~akin/cmpe160/recursion.html

http://www.cnblogs.com/etata/archive/2008/05/20/1203529.html

http://ppju.iteye.com/blog/493141

原创粉丝点击