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;
}