算法分析-----递归与分治策略

1、递归的概念

        直接或间接的调用自身的算法成为递归算法。用函数自身给出定义的函数称为递归函数。

       例1:阶乘函数

        

int factorial(int n)
{
    if(n==0) return 0;
    return n*factorial(n-1);
}

    例2:Fibonacci数列

    

int Fibonacci(int n)
{
    if(n<1) return 1;
    return Fibonacci(n-1)+Fibonacci(n-2);
}

    例3 全排列问题 

//全排列问题
/*设 R={r1,r2,…,rn} 是要进行排列的 n 个元素,Ri=R-{ri}。
集合 X 中元素的全排列记为 perm(X)。
(ri)perm(X) 表示在全排列 perm(X) 的每一个排列前加上前缀得到的排列。
R 的全排列可归纳定义如下: 
当 n=1 时,perm(R)=(r),其中 r 是集合 R 中唯一的元素;
当 n>1 时,perm(R)由 (r1)perm(R1),(r2)perm(R2),…,(rn)perm(Rn) 构成。
实现思想:将整组数中的所有的数分别与第一个数交换,这样就总是在处理后 n-1 个数的全排列。

【示例】

当 n=3,并且 E={a,b,c},则:
perm(E)=a.perm({b,c}) + b.perm({a,c}) + c.perm({a,b})
perm({b,c})=b.perm(c) + c.perm(b)
a.perm({b,c})=ab.perm(c) + ac.perm(b)
=ab.c + ac.b=(abc, acb)*/
#include <iostream>
#include <algorithm>

using namespace std;

template<class Type>
void Perm(Type list[],  int k, int m )
{ //产生[list[k:m]的所有排列
    if(k==m)
     {  //只剩下一个元素
         for (int i=0;i<=m;i++) 
     cout<<list[i];
         cout<<endl;
    }
    else  //还有多个元素待排列,递归产生排列
       for (int i=k; i<=m; i++)
        {
           swap(list[k],list[i]);
           Perm(list,k+1,m);   
           swap(list[k],list[i]);         
         }
}

int main() {
    
    char s[]="abc";
    Perm(s,0,2);

    return 0;
}

2、分治法的基本思想

    分治法的基本思想是将一个规模为n的问题分解为k个规模较小的子问题。这些子问题相互独立且与原问题相同,递归的解决这些子问题,然后将各子问题的解合并并得到原问题的解。从分治法的一般设计模式可以看出,用它设计的程序一般时递归算法。

    例1 二分搜索

    

template<class Type>
int BinarySearch(Type a[],Type &x,int n)
{
    int left,right=n-1;
    while(left<=right)
        {
            int middle=(left+right)/2;
            if(x==a[middle]) return middle;
            if(x>a[middle]) left=middle+1;
            else 
               right=middle-1;
            
        }
    return -1;//未找到
}

    例2 归并排序

  

/*归并排序是利用归并的思想,采用分治策略,将问题分为一些小问题然后递归求解。在治阶段将分阶段得到****的各答案合在一起。比如一个{8,4,5,7,1,3,6,2}的数列分成{8,4,5,7}和{1,3,6,2}之后
****再分成{8,4},{5,7},{1,3},{6,2}再分成{8}{4}{5}{7}{1}{3}{6}{2},然后开始比较先比较8,4
****小的放前面之后合并,{4,8},以此类推合并{5,7},{1,3},{2,6}再比较合并{4,5,7,8},{1,****2,3,6},再比较合并{1,2,3,4,5,6,7,8}.
****归并是稳定排序,时间复杂度nlogn。
*/
#include <stdio.h>
#include<malloc.h>
//using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
//template<class Type>
//合并
void Merge(int A[], int TmpAry[], int Lpos, int Rpos, int RightEnd)
{
	int i, LeftEnd, NumTypes, TmpPos; 
	LeftEnd = Rpos - 1;
	TmpPos = Lpos;     //临时数组指针
	NumTypes = RightEnd - Lpos + 1;
	while (Lpos <= LeftEnd&&Rpos <= RightEnd)
	{
		if (A[Lpos] <= A[Rpos])
		{
			TmpAry[TmpPos++] = A[Lpos++];
		
		}
			
		else
		{
			TmpAry[TmpPos++] = A[Rpos++];
			
		}
			

	}
	
	while (Lpos <= LeftEnd)
	{
		TmpAry[TmpPos++] = A[Lpos++];
		
	}
		
	while (Rpos <= RightEnd)
	{
		TmpAry[TmpPos++] = A[Rpos++];
		
	}
		
	//复制
	for (i = 0; i<NumTypes; i++, RightEnd--)
		A[RightEnd] = TmpAry[RightEnd];
	


}
void MSort(int A[], int TmpAry[], int left, int right)
{
	if (left<right)
	{
		int center = (left + right) / 2;
		MSort(A, TmpAry, left, center);//处理左半部
		MSort(A, TmpAry, center + 1, right);//处理右半部分
		Merge(A, TmpAry, left, center + 1, right);//合并
		
	}
}
//测试
void MergeSort(int A[], int N)
{
	int *TmpAry;
	TmpAry = (int*)malloc(N*sizeof(int));
	if (TmpAry != NULL)
	{
		MSort(A, TmpAry, 0, N - 1);
		free(TmpAry);
	}
	else
		printf("ERROR");
	//cout<<"not space for tem array!"<<endl;
}

int main(int argc, char *argv[]) {
	int i;
	int A[8] = { 6,3, 1, 2, 12, 32,16,89 };
	MergeSort(A, 8);
	for (i = 0; i<8; i++)
		//cout<<A[i]<<endl;
		printf("%d\n", A[i]);
	return 0;
}

     例3 快速排序

  

/****
****采用三数中值法选区枢纽元
****在数据小于一定值时采用插入排序可以实现更高效率的排序
****
****
****
****
****/
#include <iostream>
#define cutoff 3
/* run this program using the console pauser or add your own getch, system("pause") or input loop */
template <class Type>
void swap(Type &a, Type &b)
{
	Type temp;
	temp = a;
	a = b;
	b = temp;
}
template<class Type>
void InsertSort(Type A[], int N)
{
	int i, j;
	Type temp;
	for (i = 1; i<N; i++)
	{
		temp = A[i];
		for (j = i; j >= 0 && A[j - 1]>temp; j--)
			A[j] = A[j - 1];
		A[j] = temp;
	}
}

//以三数中值作为基准值 
template <class Type>
Type Median3(Type A[], int left, int right)
{
	int center = (left + right) / 2;
	if (A[left]>A[center])
		swap(A[left], A[center]);
	if (A[left]>A[right])
		swap(A[left], A[right]);
	if (A[center]>A[right])
		swap(A[center], A[right]);
	//以上得到A[left]<=A[center]<=A[right]
	swap(A[center], A[right - 1]);//隐藏枢纽元
	return A[right - 1];	       //返回枢纽元 
}
template <class Type>
void QSort(Type A[], int left, int right)
{
	int i, j;
	Type Pivot;
	Pivot = Median3(A, left, right);
	i = left; j = right - 1;
	if (left + cutoff <= right)
	{
		for (;;)
		{
			while (A[++i]<Pivot){}
			while (A[--j]>Pivot){}
			if (i<j)
				swap(A[i], A[j]);
			else
				break;

		}

		swap(A[i], A[right - 1]);//将枢纽元换回
		QSort(A, left, i - 1);
		QSort(A, i + 1, right);
	}
	
	
	else
	InsertSort(A+left,right-left+1);
}
int main(int argc, char *argv[]) {
	int A[10] = { 2, 5, 1, 3, 43, 6,21,32,78,76 };
	QSort(A, 0, 9);
	//QSort();
	//swap(A[0],A[1]); 
	for (int i = 0; i<10; i++)
		std::cout << A[i] << std::endl;
	return 0;
}

 

    原文作者:递归与分治算法
    原文地址: https://blog.csdn.net/zl6481033/article/details/84339335
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞