Recursion and Divide and Conquer [Data Structure and Algorithm]

Previous articles
1 Introduction-Basic Concepts of Data Structure
2 Introduction-Algorithm
3 Linear List-Sequence List and Linked List Concepts and Their Code Implementation
4 Search-Order + Half + Index + Hash
5 Insertion Sort-Hill Sort-Selection Sort-Bubble Sort-Quick Sort-Cardinal Sort-External Sort-Merge Sort

1 Definition of recursion

  • A subroutine (or function) calls itself directly or indirectly through a series of call statements, which is called recursion.
  • Recursion is a basic method of describing and solving problems.

Direct recursive call

void A()
{
    
    
 ...
	A();
 ...
}

Indirect call recursion

void B()
{
    
    
...
C();
...
}

void C()
{
    
    
 ...
	B();
 ...
}

2 Recursive and non-recursive solution of Fibonacci sequence

Tail recursion can be converted to non-recursive writing
Tail recursion means that recursion only occurs when return

Insert picture description here
Recursive solution

int f(int n)
{
    
    
	if(n<=1)
		return n;//结束条件
	else
		return(f(n-1)+f(n-2));//递归方程
} 

Non-recursive solution

int f(int n)
{
    
    
	int pre,now,next,j;
	if(n<=1)return(n);
	else
	{
    
    
		pre=0;now=1;
		for(j=2;j<=n;j++)
		{
    
    
			next=pre+now;
			pre=now;
			now=next
		}
		return(next);
  	}

}

3 Recursive and non-recursive solutions for palindrome string detection

    If a string is read from left to right and read from right to left is exactly the same (not case sensitive), then this string is called a palindrome. For example, "noon", "madam", etc. are all palindrome string.

Recursive solution

bool palindrome(string &s,unsigned h,unsigned t)
{
    
    
	if (h>=t) return 1;
	if(tolower(s[h])==tolower(s[t]))
		return palindrome(s,h+1,t-1);
	else
		return 0;
}

Non-recursive solution

bool palindrome(string &s)
{
    
    
	int h=0,t=strlen(s)-1;
	while(h<=t)
	{
    
    
		if(s[h]!=s[t])return 0;
		h++;t--;
	}
	return 1;
}

4 Divide and conquer recursion

4.1 Divide and conquer recursive thought

  • Solve these k sub-problems separately. If the scale of the sub-problem is still not small enough, then divide it into k sub-problems, and proceed recursively until the problem is small enough to find its solution easily.
  • Combine the solution of the small-scale problem that is found into the solution of a larger-scale problem, and gradually find the solution of the original problem from the bottom up.

4.2 Applicable conditions of the divide and conquer law

  • The scale of the problem can be easily solved by reducing it to a certain extent;
  • The problem can be decomposed into several smaller-scale identical problems, that is, the problem has the property of optimal substructure ( premise )
  • The solutions of the sub-problems decomposed by the problem can be combined into the solution of the problem; ( if you have the first two but not the third, you can consider using greedy algorithm and dynamic programming )
  • The sub-problems decomposed by the problem are independent of each other, that is, the sub-problems do not contain common sub-problems. ( This feature designs the efficiency of the divide-and-conquer method )

4.3 The basic steps of divide and conquer

Pay attention to the notes

{
    
    
	if ( | P | <= n0) adhoc(P); //解决小规模的问题
	divide P into smaller subinstances P1,P2,...,Pk;//分解问题
		for (i=1,i<=k,i++)
			yi=divide-and-conquer(Pi); //递归的解各子问题
		return merge(y1,...,yk); //将各子问题的解合并为原问题的解
}

4.4 Three ways to solve the recursive complexity calculation

4.4.1 Substitution method

Prerequisite (ignore the details and add them if they are found to be important later)
T(n) consists of two parts, one isSum of calculation time for each small part + Decomposition time and reconciliation time f(n)

Insert picture description here
The main idea

  1. Guess the form of the solution.
  2. Use mathematical induction to find the constant that makes the solution really effective

Insert picture description here

Insert picture description here

4.4.2 Iterative method-direct expansion

Insert picture description here

4.4.3 Main method

Insert picture description here

Insert picture description here
Insert picture description here

5 Example application

    Assuming that there are n data a[n], to print all the permutations of these n data, consider the recursive method PrintPermutation.

  1. The element at the first position may be any of these n elements. You can use swap to exchange the first position with other positions to get the difference in the first position element, and the rest of the recursive call prints all The arrangement function PrintPermutation is completed. However, it should be noted that they should be exchanged back to facilitate correct handling later.

  2. Inside the recursive function, the element at the current first position (the second position) will be exchanged with the remaining n-2 position elements; the element at the current first position (the third position) will be exchanged with the remaining n -3 position element exchange; ...; The element at the last nth position means that the previous n-1 positions have been processed and can be printed. So the recursive printing condition is position k=n, this is also a recursive exit

a[] stores the data k represents the first exchange position, generally 1, n is the number of data.

void PrintPermutation(int a[], int k, int n){
    
    
	if (k == n){
    
    
		for (int i = 1; i < n + 1; ++i){
    
    
			cout << a[i] << " ";
		}
		cout << endl;
		return;
	}
	else{
    
    
		for (int i = k; i < n+1; ++i){
    
    
			Swap(a[k], a[i]);
			PrintPermutation(a, k + 1, n);
			Swap(a[k], a[i]);
		}
	}
}


int main()
{
    
    
	int *a, len;
	cout << "len:" << endl;
	cin >> len;
	a = new int[len+1];
	if (!a)return -1;
	for (int i = 1; i < len + 1; ++i)
		a[i] = i;
	PrintPermutation(a, 1, len);
}

If there are omissions and errors, please point them out.

Guess you like

Origin blog.csdn.net/weixin_44972997/article/details/114443152