How to convert recursion to non-recursion

Source: Internet
Author: User

Recursive functions have good readability and maintainability. However, in most cases, the program is less efficient than non-recursive functions. In programming, recursive functions are generally used to solve problems, if the method is correct, it is converted to non-recursive functions to improve efficiency. When calling a function, you need to allocate a new frame in the stack and add the return address, call parameters, and local variables to the stack. Therefore, the deeper recursive calls, the more stack space occupied. If the number of layers is too deep, stack overflow will occur, which is also one of the necessity to eliminate recursion. Recursive functions can also be divided into tail recursion and non-tail recursion functions. The former has good optimization efficiency. We will discuss it separately below. The tail recursion function refers to the last operation of a function that calls the function itself. It is a special case of recursion. Tail recursion has two main features: 1. calling its own functions (Self-called); 2. Computing only occupies the Space of the constant Stack (Stack Space ). Why does tail recursion achieve constant stack space? We use the famous fibonacci series as an example to illustrate this. The implementation method of the fibonacci series is generally like this. int FibonacciRecur (int n) {if (0 = n) return 0; if (1 = n) return 1; return FibonacciRecur (n-1) + FibonacciRecur (n-2);} but note that this implementation method is not tail recursion, because the last action of tail recursion must be called itself, the final action here is the addition operation, so we need to modify it. int FibonacciTailRecur (int n, int acc1, int acc2) {if (0 = n) return acc1; return FibonacciTailRecur (n-1, acc2, acc1 + acc2);} Well, now it complies with the definition of tail recursion. It is compiled with the-O and-O2 options added to gcc respectively. The following is part of the assembly code, -O2: copy the compilation code to the FibonacciTailRec Ur :. LFB12: testl % edi, % edi movl % esi, % eax movl % edx, % esi je. l4. p2align 4, 7. l7: leal (% rax, % rsi), % edx decl % edi movl % esi, % eax testl % edi, % edi movl % edx, % esi jne. l7 // use jne. l4: rep; ret copy code-O Assemble Code copy code FibonacciTailRecur :. LFB2: pushq % rbp. LCFI0: movq % rsp, % rbp. LCFI1: subq $16, % rsp. LCFI2: movl % edi,-4 (% rbp) movl % esi,-8 (% rbp) movl % edx,-12 (% rbp) cmpl $0, -4 (% rbp) jne. l2 movl-8 (% Rbp), % eax movl % eax,-16 (% rbp) jmp. l1.L2: movl-12 (% rbp), % eax movl-8 (% rbp), % edx addl % eax, % edx movl-12 (% rbp ), % esi movl-4 (% rbp), % edi decl % edi call maid,-16 (% rbp ). l1: movl-16 (% rbp), % eax leave ret copy code. We can see that-O2 uses the jne command. No new stack space is applied for each lower-layer recursion call, instead, it updates the local data of the current frame and reuses the current frame. Therefore, no stack overflow occurs no matter how many layers of tail recursion calls are made. This is also the significance of using tail recursion. -O uses the call command to apply for a new stack space. That is to say, tail recursion is not optimized by default in gcc, one of the main reasons for doing this is that sometimes we need to retain the frame information for debugging, and after-O2 optimization, no matter how many layers of tail recursion call, the first frame is used, the information of the current frame is not available. You can use gdb to debug the frame. In addition to tail recursion, the Fibonacci series can easily export the loop implementation method. Copy the code int fibonacciNonRecur (int n) {int acc1 = 0, acc2 = 1; for (int I = 0; I <n; I ++) {int t = acc1; acc1 = acc2; acc2 + = t;} return acc1;} copy the code on my machine, add the-O2 option to optimize compilation. The running time is as follows (in microseconds). n. ononaccinonrecur. FibonacciTailRecur. FibonacciRecur. 20. 1. 123. 30. 1. 14144. Compare the performance of the function, it can be found that the iteration and tail recursion time are almost the same. The n size has little impact on the iteration and tail recursion running time, because only multiple O (n) machine commands are executed. However, n has a significant impact on recursive functions, because recursion requires frequent allocation of the recycle stack space. Due to the high efficiency of tail recursion, we recommend that you use tail recursion in some languages such as lua (refer to chapter 2 of lua program design 2 ). The non-tail recursive function compiler cannot automatically optimize General recursive functions. However, by simulating the process of recursive functions, we can use the stack to convert any recursive functions into iterative functions. Straight forward, the recursive process is actually the compiler that helps us deal with the operation of the Pressure stack and the exit stack. to convert to an iterative function, we need to manually process the pressure stack and the exit stack. The following uses the classic quick sorting as an example. Copy the code int partition (int * array, int low, int high) {int val = array [low]; while (low

Related Article

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.