Recursion and Iteration _1 2016.4.21

Source: Internet
Author: User
Tags mathematical functions

iterative is artificial, recursive avatar

To Interate is Human,to recurse,divine

First, the definition

(1)
Iteration
is an activity that repeats the feedback process and is usually intended to approximate the desired target or result
Each repetition of a process is called an iteration, and the results of each iteration are the initial values of the next iteration

(2)

Programming skills called recursion (recursion) for program calls

A procedure or function has a method of directly or indirectly invoking itself in its definition or description, which usually transforms a large and complex problem layer into a smaller problem similar to the original problem, and the recursive strategy can describe the repeated computations needed in the process of solving the problems by a small number of programs. Greatly reduces the amount of code in the program

The ability to recursively define an infinite set of objects with limited statements

In general, recursion requires boundary conditions, recursive forward segments, and recursive return segments
Recursive progression when boundary conditions are not met
Recursive return when boundary conditions are met

Ii
Recursion, which is to call yourself in the process of running
The conditions that make up a recursive requirement:
1. Sub-problem should be the same as the original problem, and more simple
2. Cannot call itself indefinitely, must have a recursive export, degenerate to non-recursive state processing


The Fibonacci sequence is a typical recursive case:

Fib (0) = 1 [Basic situation]
Fib (1) = 1 [Basic situation]
Integer to all n > 1: fib (n) = (fib (n-1) + fib (n-2)) [recursive definition]

Although there are many mathematical functions that can be represented recursively, the high overhead of recursive definitions is often prohibitive in practical applications

Factorial (1) = 1 [Basic situation]
Integer to all n > 1: factorial (n) = (n * factorial (n-1)) [recursive definition]


An easy-to-understand psychological model
Is that a recursive definition defines an object as defined by a "previously defined" class object.

For example: How can you move 100 boxes?
Answer: You first move a box, and note where it moves to
Then solve the smaller problem: how can you move 99 boxes?
Eventually, your question becomes how to move a box, and you already know what to do.

Second, C language to the support of recursion

Because of the call stack used, the C language naturally supports recursion

In a C-language function, there is no essential difference between calling yourself and calling other functions, creating a new stack frame, passing parameters and modifying the "Current line of code"

Delete the stack frame after the function has finished executing, process the return value and modify the "Current line of code"


The following analogy can be made:

Emperor (stack frame with Mian function): minister, you give me a count. F (3)
Minister (with stack frame of F (3)): Magistrate, you give me a count. F (2)
The magistrate (owns the stack frame of F (2)): Magistrate, you give me a count. F (1)
Magistrate (Stack frame with F (1)): Touts, you give me a count. F (0)
Touts (with a stack frame of f (0)): Back to Master, f (0) = 1
Magistrate: (Mental arithmetic f (1) = f (0) * = 1) Back to the mansion Monseigneur, f (1) = 1
Magistrate: (Mental arithmetic f (2) = f (1) * = 2) Back to Monseigneur, f (2) = 2
Minister: (Mental arithmetic f (3) = f (2) * = 6) Return to the Emperor, F (3) = 6
The emperor was satisfied.

Do not understand the call stack, do not need to-know the recursion why the normal work on the line

The focus of the design recursion program is to arrange work for subordinates

Each recursive call needs to add a stack frame to the call stack, which crosses over over time.
Use the term to call it stack overflow (stack Overflow)

Local variables are also placed on the stack segment, so it is recommended to "put larger arrays outside the main function"

Stack overflow is not necessarily a recursive call too much, or it may be too large for local variables

Stack overflow is generated as long as the total size exceeds the allowable range

Three, the characteristics, the difference

Recursive algorithm is a process of invoking its own algorithm directly or indirectly.
In computer programming, recursive algorithm is very effective to solve a large class of problems, it often makes the description of the algorithm concise and easy to understand

The recursive algorithm solves the problem characteristic:
(1)
Recursion is invoking itself in a procedure or function.
(2)
When using a recursive strategy, there must be a definite recursive end condition called a recursive exit
(3)
Recursive algorithm is usually very concise, but the recursive algorithm is less efficient in solving problems
Therefore, the recursive algorithm is generally not advocated for the design of the program.
(4)
In the process of recursive invocation, the system opens up stacks for each layer's return point, local quantity, etc. to store
Too many recursion times can cause stack overflow and so on

Iv. Recursive applications

(1) The definition of data is defined recursively (Fibonacci function)
(2) Problem solving method is implemented by recursive algorithm
Although there is no obvious recursive structure in this kind of problem, it is simpler to solve it by recursion than iterative solution, such as Hanoi (Hanoi) problem
(3) The structural form of the data is defined recursively
such as binary tree, generalized table, etc., due to the inherent recursive nature of the structure, their operations can be recursively described

Disadvantages of recursion:
The algorithm of recursive algorithm is relatively common, such as ordinary cycle, and the operation efficiency is low.
Therefore, recursion should be avoided as much as possible, unless there is no better algorithm or a particular situation, and recursion is more appropriate.
In the process of recursive invocation, the system opens up stacks for each layer's return point, local quantity, etc. to store
Too many recursion times can cause stack overflow and so on

V. Linear recursion

(1)
Array summation: Iteration
Problem: Calculates the sum of a given n integers
Implementation: One after the other to take out elements, tired plus

int Sum(intint n){    intsum0;    for (int i=0; i<n; ++i) {        sum += num[i];    }    returnsum;}

Array summation: Recursion

If n = 0 The sum must be 0, which is also the final ordinary situation
Otherwise generally, the sum can be understood as n-1 of the first integer (Num[0, n-1]) plus the end element (Num[n-1])

According to this idea, the algorithm can be designed based on the linear recursive pattern.

int  Sum ( int  num[], int  N) / /Array summation algorithm (linear recursive version)  {if  (N < 1 ) {//trivial case, recursive base  return  0 ; //Direct (non-recursive) calculation } else  {//general case  return  Sum (num, N-1 ) + num[n-1 ]; //recursion: The sum of the former n-1 items, and then accumulate the n-1 item }} //o (1) * Recursive depth = O (1) * (n+1) = O (n)   

From this example, we can see the basic techniques to ensure the poor nature of recursive algorithm:
First judge and deal with the trivial case of n = 0, lest the system overflow due to infinite recursion
Such trivial situations are collectively referred to as the "recursive base" (base case of recursion)
There may be a variety of mundane situations, but at least one (such as here), and sooner or later it will inevitably appear

(2)
linear recursion
The algorithm sum () may be self-invoking at a deeper level, and each recursive instance calls itself at most once
So there is at most one instance at most on each level, and they form a linear order relationship
Such recursive patterns are thus referred to as "linear recursion" (linear recursion)
It is also the most basic form of recursion

In this form, application problems can always be decomposed into two separate sub-problems:
One corresponds to a single element, so it can be solved directly (e.g. num[n-1])
The other corresponds to the remainder, and its structure is the same as the original problem (e.g. Num[0, n-1])
In addition, the solution of the sub-problem can be solved by simple merging (for example, integer addition).

the reduction and treatment of
The linear recursive pattern, which often corresponds to the algorithm strategy of the so-called Reduction and Cure (Decrease-and-conquer):
Each step in the recursion, the scale of the problem is reduced to a constant, until the final degenerate into trivial small (simple) problems

In accordance with the strategy of the reduction, the invocation parameters will be monotonically linearly decreasing as the recursion goes further.
So no matter how large the initial input n is, the total number of recursive calls is limited, and the execution of the estimation method will sooner or later terminate, both to satisfy the poor
When the recursive base is reached, the algorithm performs a non-recursive calculation (here is the return 0)

Vi. Recursive analysis

Recursive algorithm the analysis of time and space complexity is very different from the conventional algorithm, and has its own laws and specific skills.
The two main methods of recursive tracking and recursive equations are described below.

(1) recursive tracking
As an intuitive and visual method, recursive tracking (recursion trace) can be used to analyze the overall run time and space of the recursive algorithm
Intuitive image for simple recursive mode only

Recursive tracking (recursion trace) analysis
Check each recursive instance
In addition to calling the statement itself, the time required to count other code
The sum of which is the algorithm execution time

The flexibility of C syntax will bring some difficulties to analysis//Read Code + Compliance specification

The calculation time required for the entire algorithm should be equal to the sum of the time required to create, execute, and destroy all recursive instances
Among them, the creation and destruction of recursive instances are the responsibility of the operating system, the corresponding time cost can usually approximate to the constant, and will not exceed the time cost of the actual calculation step in the recursive instance, so it is often neglected
For ease of estimation, the time required to start each recursive invocation statement for each instance can also be counted into the account of the created recursive instance
So we just need to count the time required for the non-recursive invocation part of each recursive instance

Specifically, in terms of the sum () algorithm above, the calculation of the non-recursive part of each recursive instance involves no more than three classes (judging whether n is 0, summing sum (n-1) and Num[n-1], returning the current sum), and at most one time
Since they are all basic operations, each recursive instance should actually take a time of O (3)

For input arrays of length n, the recursion depth should be n+1
Therefore, the entire sum algorithm run time is:
(n + 1) * O (3) = O (3 * (n + 1)) = O (n)

The spatial complexity of the algorithm:
When the last recursive instance is created (that is, to the recursive base), the amount of space occupied is maximized – accurately, equal to the sum of the amount of space each recursive instance occupies
The data to be stored for each recursive instance here is nothing more than a call parameter (the starting address and length of the data) and a temporary variable for the summation sum
Each of these data requires only a constant size of space, and its total amount should also be constant
Therefore, the spatial complexity of the Sum () algorithm is linearly proportional to its recursion, i.e. O (n)

(2) recursive equations (indirect abstraction, more suitable for complex recursive patterns)
Another common analysis method of recursive algorithm, namely the recursive equation (recurrence equation) method
In contrast to recursive tracking analysis, the method does not need to draw a specific calling process, but rather the mathematical induction of recursive patterns, the derivation of the recursive equations (groups) of the bound functions of the complexity and their boundary conditions, thus the analysis of complexity is transformed into the solution of the recursive equation (group).

In general, the method is quite similar to the differential equation method:
The expression of many complex functions is usually not easy to obtain directly, but their differential forms tend to follow some relatively concise laws, by solving a set of differential equations describing these laws, we can finally derive the explicit representation of the original function.
The solution of a differential equation is usually not unique unless a sufficient number of boundary conditions are given

Similarly, in order to give a definite solution to the recursive equation of the complex bound function, some boundary conditions are also required.

Boundary conditions can often be obtained by the analysis of recursive bases

(3)
Find the largest element: iteration
Problem: In a given n integer, find the largest
Algorithm Max (num[], N): Checks each element individually, retains the largest
O (N)

int Max(intint n){    int Max = num[0];    for (int i=1; i<n; ++i) {        if (num[i] > Max) {            Max = num[i];        }    }    return Max;}

Find the largest element: recursion

int Max(intintint high){    if (low == high) {        return num[low];    else {        int2;        returnmax(Max(num, low, mid), Max(num, mid+1, high));    }}

From a recursive point of view, to solve Max (num, lo, HI)
Need to solve Max (num, lo, MI) and Max (num, mi+1, HI) recursively
And then take the larger in the solution of the sub-problem.
Recursive base: Max (Num, lo, lo)

Seven, recursive mode

(1) Multi-recursive base
In order to be poor, recursive algorithms must set up a recursive base and ensure that it always executes to
For this reason, it is necessary to set up the corresponding recursive base for each kind of trivial situation that may occur.
Therefore, the recursive base of the same algorithm may be (explicitly or implicitly) more than one

The inverse of the array, that is, the order of the elements in the array is reversed before and after.
For example, if the input array is: a[] = {3, 1, 4, 1, 5, 9, 2, 6}
Then inverted: a[] = {6, 2, 9, 5, 1, 4, 1, 3}

void Reverse(intintint high)   //数组倒置(多递归基迭代版){    if (low < high) {        swap(num[low], num[high]);  //交换num[low]和num[high]        Reverse(num, low+1, high-1);    //递归倒置num(low, high)    }   // else 隐含了两种递归基}   //O(high - low + 1) 
void Reverse(intintint high)   //数组倒置 迭代版{    while (low < high) {        swap(num[low], num[high]);        ++low;        --high;    }}

(2) implementing recursion
When designing a recursive algorithm, it is often necessary to try again and again from multiple angles to determine the optimal partitioning of the input and scale of the problem.
At times, it may be necessary to redefine and describe the original problem from different angles, so that the sub-problems obtained by decomposition have the same semantic form as the original problem.

For example, in the linear iterative version of the reverse () algorithm, by introducing the parameter low and high, recursive calls to all groups and subsequent sub-arrays are unified into the same syntactic form

(3) Multi-directional recursion
Recursive algorithms, not only recursive bases may have multiple, recursive calls may also have a variety of branches to choose from

In the following simple example, each recursive instance has multiple possible recursion directions, but only one can choose from it, so the recursive instances at each level still form a linear order relationship, which still belongs to the linear recursion

typedeflonglong LL;
LL power2(int n)    //幂函数2^n算法(暴力迭代版),n>=0{    pow1;    while0) {        --n;        pow1;    }    returnpow;}   //O(n) = O(2^r) r为输入指数n的比特位数
LL power2(int n)    //幂函数2^n算法(线性递归版),n>=0{    if0) {        return1;    else {        return power2(n-1)*2;    }}   //O(n)

In fact, if we can analyze the function from other angles and give a new recursive definition, we can complete the calculation of power function more quickly.

Here is an example:
Power2 (N)
if n = 0,power2 (n) = 1
If n >0 and Odd,power2 (n) = Power2 (? n/2?) ^2 * 2
If n > 0 and Even,power2 (? N/2?) ^2

According to this new expression and understanding, we can expand the bits after n by binary, and get Power2 (n) by repeated square operation and doubling operation.

Like what:

2^1 = 2^001 (b) = (2^2^2) ^0 * (2^2) ^0 * 2^1 = ((((1 * 2^0) ^2 * 2^0) ^2 * 2^1)

2^2 = 2^010 (b) = (2^2^2) ^0 * (2^2) ^1 * 2^0= (((1 * 2^0) ^2 * 2^1) ^2 * 2^0)

2^3 = 2^011 (b) = (2^2^2) ^0 * (2^2) ^1 * 2^1 = ((((1 * 2^0) ^2 * 2^1) ^2 * 2^1)

2^4 = 2^100 (b) = (2^2^2) ^1 * (2^2) ^0 * 2^0 = ((((1 * 2^1) ^2 * 2^0) ^2 * 2^0)

2^5 = 2^101 (b) = (2^2^2) ^1 * (2^2) ^0 * 2^1 = ((((1 * 2^1) ^2 * 2^0) ^2 * 2^1)

2^6 = 2^110 (b) = (2^2^2) ^1 * (2^2) ^1 * 2^0 = ((((1 * 2^1) ^2 * 2^1) ^2 * 2^0)

2^7 = 2^111 (b) = (2^2^2) ^1 * (2^2) ^1 * 2^1 = ((((1 * 2^1) ^2 * 2^1) ^2 * 2^1)
。。。

In general, if the binary expansion of n is B1B2B3...BK, then there is
2^n = (... (((((1 * 2^b1) ^2 * 2^b2) ^2) * 2^b3) ^2 ... * 2^bk)

If the binary expansion of Nk-1 and NK is b1b2...bk-1 and B1B2...BK-1BK, respectively, there is
2^nk = (2^nk-1) ^2 * 2BK

This concludes the following recursive formula:
Power2 (NK)
If BK = 1,power2 (NK) = Power2 (nk-1) ^2 * 2
If BK = 0,power2 (NK) = Power2 (nk-1) ^2

inline LL squre(LL a){    return a*a;}LL power2(int n)    //幂函数2^n算法(优化递归版),n>=0{    if0) {        return1;   //递归基;否则,视n的奇偶分别递归    else {        return (n&1) ? squre(power2(n>>11 : squre(power2(n>>1));    }}   //O(logn) = O(r),r为输入指数n的比特位数

There are different recursive directions for the two possibilities of an odd or even number of input parameter n
However, each recursive instance can only go down One direction to the lower recursion
So it still belongs to linear recursion.

The time complexity of the algorithm is:
O (logn) * O (1) = O (Logn) = O (r)

The computational efficiency has been greatly improved compared to the previously violent version of O (n) = O (2^r).

LL power(intint n)    //幂函数x^n算法(迭代优化版),n>=0{    pow1;    LL t = x;    while (n) {        if (n&1) {            pow *= t;        }        t *= t;        1;    }    returnpow;}   //O(logn) = O(r),r为输入指数n的比特位数

Selected from:
Data structure (c + + language version) (third edition) Deng Junhui
"Algorithmic Competition Primer Classic" Rujia
Baidu Encyclopedia
Blog (Forget the time to save the URL, really embarrassed)
Slightly changed

Recursion and Iteration _1 2016.4.21

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.