惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Cloudbric
Cloudbric
E
Exploit-DB.com RSS Feed
SecWiki News
SecWiki News
Forbes - Security
Forbes - Security
N
News | PayPal Newsroom
S
Security @ Cisco Blogs
Schneier on Security
Schneier on Security
V
V2EX - 技术
S
Secure Thoughts
W
WeLiveSecurity
Google DeepMind News
Google DeepMind News
C
CERT Recently Published Vulnerability Notes
NISL@THU
NISL@THU
S
Securelist
S
Security Archives - TechRepublic
Know Your Adversary
Know Your Adversary
V
Vulnerabilities – Threatpost
Security Latest
Security Latest
Recent Commits to openclaw:main
Recent Commits to openclaw:main
G
GRAHAM CLULEY
H
Hacker News: Front Page
Microsoft Azure Blog
Microsoft Azure Blog
I
Intezer
Google Online Security Blog
Google Online Security Blog
美团技术团队
阮一峰的网络日志
阮一峰的网络日志
T
The Exploit Database - CXSecurity.com
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Webroot Blog
Webroot Blog
Jina AI
Jina AI
Engineering at Meta
Engineering at Meta
P
Proofpoint News Feed
The Cloudflare Blog
I
InfoQ
L
LangChain Blog
U
Unit 42
P
Proofpoint News Feed
S
Schneier on Security
S
Security Affairs
Y
Y Combinator Blog
T
Tenable Blog
N
News and Events Feed by Topic
MyScale Blog
MyScale Blog
量子位
Google DeepMind News
Google DeepMind News
Cyberwarzone
Cyberwarzone
博客园 - 聂微东
D
Darknet – Hacking Tools, Hacker News & Cyber Security
GbyAI
GbyAI
AWS News Blog
AWS News Blog

博客园 - sundeepblue

const 堆和栈的区别 (转贴) The Linux Alternative Project Linux与windows 互访总结 Airplane: Cool!!! Lyx: The Document Processor! VC快捷键 几个一定要掌握的string 函数 **A Tree Manipulation Library What is Recursion? How to Rewrite Standard Recursion through a State Stack & Iteration Recursive 使用SIMD指令高度优化Matrix类(in C++) 发挥缓存的威力,提高代码效率,及如何实现16位浮点数 Inline Assembly in VC++ and gcc 写Makefile IQ, EQ, AQ & 阿Q 编写C/C++程序需要知道的基本问题 快速求平方根的算法
Iteration Vs. Recursion
sundeepblue · 2007-10-07 · via 博客园 - sundeepblue

 

A recursive method is a method that calls itself either directly or indirectly

There are two key requirements to make sure that the recursion is successful:

  • Every recursive call must simplify the computation in some way.
  • There must be special cases to handle the simplest computations.

Iteration Vs. Recursion

  • If a recursive method is called with a base case, the method returns a result. If a method is called with a more complex problem, the method divides the problem into two or more conceptual pieces: a piece that the method knows how to do and a slightly smaller version of the original problem. Because this new problem looks like the original problem, the method launches a recursive call to work on the smaller problem.
  • For recursion to terminate, each time the recursion method calls itself with a slightly simpler version of the original problem, the sequence of smaller and smaller problems must converge on the base case. When the method recognizes the base case, the result is returned to the previous method call and a sequence of returns ensures all the way up the line until the original call of the method eventually returns the final result.
  • Both iteration and recursion are based on a control structure: Iteration uses a repetition structure; recursion uses a selection structure.
  • Both iteration and recursion involve repetition: Iteration explicitly uses a repetition structure; recursion achieves repetition through repeated method calls.
  • Iteration and recursion each involve a termination test: Iteration terminates when the loop-continuation condition fails; recursion terminates when a base case is recognized.
  • Iteration and recursion can occur infinitely: An infinite loop occurs with iteration if the loop-continuation test never becomes false; infinite recursion occurs if the recursion step does not reduce the problem in a manner that converges on the base case.
  • Recursion repeatedly invokes the mechanism, and consequently the overhead, of method calls. This can be expensive in both processor time and memory space.

Types of Recursion


RECURSION - A method of programming whereby a function directly or indirectly calls itself. Recursion is often presented as an alternative to iteration.

LINEAR RECURSION - Recursion where only one call is made to the function from within the function (thus if we were to draw out the recursive calls, we would see a straight, or linear, path).

A linear recursive function is a function that only makes a single call to itself each time the function runs (as opposed to one that would call itself multiple times during its execution). The factorial function is a good example of linear recursion.

;Scheme
            (define (factorial n)
            (if (= n 0)
            1
            (* n (factorial (- n 1)))
            )
            )          
//C++
            int factorial (int n)
            {
            if ( n == 0 )
            return 1;
            return n * factorial(n-1); // or factorial(n-1) * n
            }          

TAIL RECURSION - A recursive procedure where the recursive call is the last action to be taken by the function. Tail recursive functions are generally easy to transform into iterative functions.

Tail recursion is a form of linear recursion. In tail recursion, the recursive call is the last thing the function does. Often, the value of the recursive call is returned. As such, tail recursive functions can often be easily implemented in an iterative manner; by taking out the recursive call and replacing it with a loop, the same effect can generally be achieved. In fact, a good compiler can recognize tail recursion and convert it to iteration in order to optimize the performance of the code.

A good example of a tail recursive function is a function to compute the GCD, or Greatest Common Denominator, of two numbers:

;Scheme
            (define (gcd m n)
            (cond
            ((< m n) (gcd n m))
            ((= (remainder m n) 0) n)
            (else (gcd n (remainder m n)))
            )
            )          
//C++
            int gcd(int m, int n)
            {
            int r;
            if (m < n) return gcd(n,m);
            r = m%n;
            if (r == 0) return(n);
            else return(gcd(n,r));
            }          

BINARY RECURSION - A recursive function which calls itself twice during the course of its execution.

Some recursive functions don't just have one call to themself, they have two (or more). Functions with two recursive calls are referred to as binary recursive functions.

The mathematical combinations operation is a good example of a function that can quickly be implemented as a binary recursive function. The number of combinations, often represented as nCk where we are choosing n elements out of a set of k elements, can be implemented as follows:

;Scheme
            (define (choose n k)
            (cond
            ((= k 0) 1)
            ((= k n) 1)
            (else   (+     (choose (- n 1) k)  (choose (- n 1) (- k 1))   )     )
            )          
//C++
            int choose(int n, int k)
            {
            if (k == 0 || n == k) return(1);
            else return(choose(n-1,k) + choose(n-1,k-1));
            }					

EXPONENTIAL RECURSION - Recursion where more than one call is made to the function from within itself. This leads to exponential growth in the number of recursive calls.

An exponential recursive function is one that, if you were to draw out a representation of all the function calls, would have an exponential number of calls in relation to the size of the data set (exponential meaning if there were n elements, there would be O(an) function calls where a is a positive number).

A good example an exponentially recursive function is a function to compute all the permutations of a data set. Let's write a function to take an array of n integers and print out every permutation of it.

//C++
            void print_array(int arr[], int n)
            {
            int i;
            for(i=0; i<n; i++) printf("%d ", arr[i]);
            printf("\n");
            }
            void print_permutations(int arr[], int n, int i)
            {
            int j, swap;
            print_array(arr, n);
            for(j=i+1; j<n; j++) {
            swap = arr[i]; arr[i] = arr[j]; arr[j] = swap;
            print_permutations(arr, n, i+1);
            swap = arr[i]; arr[i] = arr[j]; arr[j] = swap;
            }
            } 			

NESTED RECURSION

In nested recursion, one of the arguments to the recursive function is the recursive function itself! These functions tend to grow extremely fast. A good example is the classic mathematical function, Ackermann's function. It grows very quickly (even for small values of x and y, Ackermann(x,y) is extremely large) and it cannot be computed with only definite iteration (a completely defined for() loop for example); it requires indefinite iteration (recursion, for example).

Try computing ackerman(4,2) by hand... have fun!

//C++
            int ackerman(int m, int n)
            {
            if (m == 0) return(n+1);
            else if (n == 0) return(ackerman(m-1,1));
            else return(ackerman(m-1,ackerman(m,n-1)));
            } 			

MUTUAL RECURSION

A recursive function doesn't necessarily need to call itself. Some recursive functions work in pairs or even larger groups. For example, function A calls function B which calls function C which in turn calls function A.

A simple example of mutual recursion is a set of function to determine whether an integer is even or odd. How do we know if a number is even? Well, we know 0 is even. And we also know that if a number n is even, then n - 1 must be odd. How do we know if a number is odd? It's not even!

//C++
            int is_even(unsigned int n)
            {
            if (n==0) return 1;
            else return(is_odd(n-1));
            }
            int is_odd(unsigned int n)
            {
            return (!is_even(n));
            } 			

Recursion is powerful! Of course, this is just an illustration. The above situation isn't the best example of when we'd want to use recursion instead of iteration or a closed form solution. A more efficient set of function to determine whether an integer is even or odd would be the following:

//C++
            int is_even(unsigned int n)
            {
            if (n % 2 == 0) return 1;
            else return 0;
            }
            int is_odd(unsigned int n)
            {
            if (n % 2 != 0) return 1;
            else return 0;
            }