Converting a recursive function to a non-recursive form

Source: Internet
Author: User
Tags goto
1. Recursive invocation principle: divide and conquer

To ask for a large-scale problem, you can:
(1) Dividing the original problem into several sub-problems
(2) Sub-problem scale is small to a certain program, can be directly solved, that is, the condition of the existence of recursive termination, called recursive export.
(3) The sub-problems of the original problem decomposition always move towards the export of recursion
(5) After solving the sub-problem, we can combine the solution of the sub-problem to obtain the solution of the original problem. 2. Using mechanical methods to convert recursion to non-recursive criteria

A mechanical method is a fixed set of rules for converting any recursive function to a non-recursive function, which can be used to convert any recursive function to a non-recursive function.
Basic principle:
(1) When a recursive function call is encountered but has not yet reached its recursive exit condition, it is necessary to save all the field information of the function, including the function parameters and local variables, to the stack.
If the recursive function has a return value, the return value needs to be passed in as a parameter, and the parameter is stored in the stack. Like what:

int exmp (int n)
{   
     if (n<2)
         return n+1;
     else
         return EXMP (N/2) * EXMP (N/4);
}

Need to be converted to:

void exmp (int n,int& f)
{
    int u1,u2;
    if (n<2)
        f = n+1;
    else
    {
        exmp (N/2,U1);
        EXMP (N/4,U2);
        f = u1*u2;
    }
}

It is necessary to put the parameter n f and the local variable u1 u2 into the stack when the stack is pressed.
(2) A function call corresponds to a data element in the stack. If the parameters and local variables have multiple data, they can be placed in the structure.
(3) When a function call returns, the stack data corresponding to the function needs to be stacked to restore the caller's field information, and if the data needs to be returned, the return value needs to be placed in the caller's corresponding stack data. The solution of the original problem can be solved by using the solution of the sub-problem.
(4) The current function information must be stored in the top of the stack, and its caller information is stored in its previous data. The order in which stack data is arranged from the top of the stack to the bottom of the stack is the reverse order of the call relationships between functions. 3. Use mechanical methods to convert recursion to non-recursive steps:

(1) Set up a work stack to record the site information .
All parameters, local variables that appear in the recursive function must be replaced with the corresponding data members in the stack, and the Return Statement label Field RD (if the recursive function calls the T-sub function, then Rd takes the value 0~t+1). This information can be stored in one structure:

typedef struct ELEM {//Stack data element type
int rd;  the label of the return statement
DATATYPEOFP1 P1;      Function parameters ...
datatypeofpm pm;
DATATYPEOFQ1 Q1;      Local variables ... 
DATATYPEOFQN qn; 
} ELEM;

(2) Set T+2 statement label, which is label 0 ~ label T+1
Label 0: The first executable statement of a recursive function, typically a statement that satisfies a recursive exit condition
Label T+1: Located at the end of the function body, this is called when each recursive function returns. The function is: what needs to be done before the handler returns.
Label I (1<=I<=T): The first recursive sub-function that executes when the end of the return is executed, usually pops up the stack information of the current function and passes the result back to the caller
(3) Increase non-recursive entry
Handles the first recursive function call and saves the function arguments to the stack. Which rd=t+1. The statement is: S.push (t+1,p1,... pm,q1,... qn)
(4) replacing the recursive rules of I=1 I (,..., t)
Assume that the function body in which I (I=1, ..., t) a recursive call statement is: RECF (a1, A2, ..., am), and replace with the following statement:

S.push (i, A1, ..., am);//argument into the Stack
goto label 0;
Label i:x = S.top (); S.pop ();
          ...

Here label I handles the actions that need to be taken when the I recursive function returns. can call x = S.top (); S.pop (); POPs the stack information of the current function. If there is data to pass to the caller, you can continue calling S.top () to get the caller's data and assign it a value.
(5) Recursive exit Add Statement goto label T+1
(6) Add a statement labeled T+1
The statement for the label t+1 is fixed: Returns the address according to the Recursive Rd jump to the corresponding label. If case t+1, indicates that the topmost function call has been processed, the function ends.

Switch ((X=s.top ()). Rd) {case
0:  goto label 0;
break;
Case 1:goto label 1;
break;
.... case
T+1:item = S.top (); S.pop (); return break
;
Default:break;
}

(7) Overwrite recursion in nesting and looping
For nested recursive calls. For example, RECF (... recf ()) should read:

Exmp1= recf ();
exmp2= RECF (EXMP1);
..... exmpk= RECF (exmpk-1)

Then apply rule 4 to resolve
For recursion in the loop, write the equivalent goto loop
(8) optimized processing
Since (1) ~ (6) The function written using the goto statement, according to the flowchart to find the corresponding loop structure, thereby eliminating goto statement 4. Mechanical non-recursive implementation of pre-EXMP function optimization:

typedef struct ELEM//Store recursive function field information {INT rd;       Returns the label of the statement, rd=0~t+1 int pn,pf;       The function parameter, PN, indicates that the parameters n,pf the parameter f int q1,q2;
Local variables, Q1 means that U1,Q2 represents U2}elem;
    Class Nonrec {private:std::stack<elem> S;
        Public:nonrec (void) {} void Replace1 (int n,int& f);
void Replace2 (int n,int& f);
};
    void Nonrec::replace1 (int n,int& f) {ELEM x,tmp;                       x.rd=3;
    Because EXMP within a total of 2 recursive sub-functions, t=2, so td=t+1=3, pressure to the bottom of the stack as a monitoring whistle x.pn=n;                    S.push (x); Call the start function, recursive total entry. Equivalent to calling EXMP (7,f) label0:if ((x = S.top ()). PN < 2)//processing recursive exits, all recursive exits need to increment the statement goto label T+1.             
        This is also the first executable statement of the recursive statement {s.pop ();         X.PF = x.pn + 1;
        Get the solution pf S.push (x) of the function;             Goto Label3;                 Because the recursive exit statement needs to handle the return of the function after execution, and lable t+1 is used to handle the function return needs to do the work, so need goto lable3} x.rd = 1;
       Call the first recursive function, which is located at the back of label0, so if the recursive exit is not satisfied it will be called here until the recursive exit X.PN = (int) (X.PN/2) is satisfied; S.push(x);              One call uses a stack of data goto label0;           After the call begins to enter the inside of the function, the first execution statement of the function is located in Lable0, so goto label0 label1:tmp = S.top () is required;                 
        Label1 processing of the return of the 1th recursive function, usually a pop's own data, and then put the results of the calculation in the caller's corresponding data s.pop ();
        x = S.top ();
        S.pop ();           X.Q1 = TMP.PF;

        Gets the result of the 1th recursive function calculation and passes back to the Q1 S.push (x) of the upper function;                X.rd = 2; 
        Call a second recursive function x.pn = (int) (X.PN/4);
        S.push (x);

Goto label0;           Label2:tmp = S.top ();
        Returns a S.pop () from the second recursive function;
        x = S.top ();
        S.pop ();
        X.Q2 = TMP.PF;
        X.PF = x.q1 * X.Q2;
S.push (x);
            LABEL3://Recursive exit (LABEL0) will be called Here Switch ((X=s.top ()). Rd) {Case 1:
            Goto Label1;
            Break
            Case 2:goto Label2;
            Break
            Case 3: Label at//t+1: Indicates the entire function ends with TMP = S.top ();
            S.pop (); f = tMP.PF;
            The result of the final calculation is break;
        Default:break; }
}
5. Remove goto post-optimization non-recursive implementation steps

By removing the 4 goto statement, the optimized non-recursive implementation step can be obtained. However, the following description steps use some of the terms of the tree, such as the root node, the leaf node, and the node. This is because we can consider the recursive function as a tree node, the call relationship between functions as the edge of the tree node, the function satisfies the recursive exit condition as a leaf node, and the entrance function as the root node.
Here is a call graph that describes a recursive function with a tree that calls 3 sub-functions inside the recursive function. Where 1~30 represents the order in which functions are called down and up backwards. It is also the order in which the tree nodes are sequentially traversed.

The optimized non-recursive implementation steps are:
(1) Add non-recursive entry, press the first node of the stack. This node is the root node.
(2) continually "call down" the recursive function until it finds a leaf node that satisfies the recursive exit condition, such as A1->b1->c1->d1
(3) Processing of functions satisfying recursive exits
(4) After a function has been processed, it needs to backtrack to the parent node and find a new handler based on the parent node. This needs to be considered in two cases depending on whether it is the last calling function of the caller. If it is not the last Call function (for example, C1 calls the D1 D2 D3 three sub-functions, D1 will need to process D2 after processing, it is not the caller's last Call function) to follow the steps (5) to deal with; if so (for example, D3 is the last call to C1 function), Indicates that its parent node can be processed. After the parent node finishes processing, it is necessary to continue backtracking to the grandparent node to see if the parent node is the last child of the grandparent node, and if so, the grandparent node can also be processed. This process loops until you find an ancestor node that is not the last node.
This process ends with two results: (1) The resulting ancestor is the root node. For example, D6 through step 28->29->30, reached the root node A1, function end; (2) Get an ancestor node that is not the last node and it is not the root node, such as D3->C1,C1 is not the last node of B1. Once this ancestor node is obtained, it is processed as follows (5).
(5) If the function is not the caller's last call function, backtracking to the parent node, according to the parent node to find its next sibling node, the information of the sibling node stack
(6) return to (1) until step (4) returns to the root node

You can return to step (1) only after you have newly push a function's information in the stack. The
distinguishes between (5) and (6) cases because the backtracking node of the new node in
(5) does not change, and the new node's backtracking point is still its parent node, and does not need to backtrack upward. and (6) after processing the last node will cause the parent node to be out of the stack that the backtracking node has changed, need to find a new backtracking node and according to the new backtracking node to find a new processing node.
from the above steps we know that the tree node stored in the stack must be from the root to the new stack node in the path of all nodes. 6. Non-recursive implementation of EXMP after optimization:

void Nonrec::replace2 (int n,int& f) {ELEM x,tmp;
    X.RD = 3;
    X.PN = n;
    S.push (x);
        Do {while (X=s.top ()). PN >= 2)//constant "call down" to the recursive function until the export condition is met.
            {x.rd = 1;
            X.PN = (int) (X.PN/2);
        S.push (x);                    } x = S.top ();
        Satisfies the export condition, calculates the function the solution s.pop ();                X.PF = x.pn + 1; The calculated value is saved in PF so that it can be used by its upper-level callers.

        Its caller data holds the previous layer of S.push (x) corresponding to the stack data; while ((x = S.top ()). Rd = = 2)//Meet export conditions, you need to backtrack to the Father node.
            There are two scenarios to consider, which are considered to be the last node of the father, the case of rd==2 {tmp = S.top ();
            S.pop ();
            x = S.top ();
            S.pop ();
            X.Q2 = TMP.PF;
            X.PF = x.q1 * X.Q2;
        S.push (x); } if ((x = S.top ()). Rd = = 1)//Meet export conditions, you need to backtrack to the Father node.
            Here consider the case where the node is not the last node of the Father node {tmp = S.top ();
            S.pop ();
            x = S.top ();
            S.pop ();
  X.Q1 = TMP.PF;          S.push (x);
            Tmp.rd = 2;
            TMP.PN = (int) (X.PN/4);
        S.push (TMP);
    }}while ((x = S.top ()). Rd!=3);
    x = S.top ();
    S.pop ();    
f = x.pf; }
7. Reference

Peking University Ming Zhang Teacher "data structure and algorithm" Public course "recursive transfer non-recursive"

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.