分治法的总体思想是:
划分:将一个大的、难以直接解决的问题划分成k个规模较小的、相同的子问题。
如果这k个子问题的规模还不够小,则再划分成k个子问题,
直到问题的规模足够小,很容易直接求出其解为止
求解:对这K个子问题分别求解
合并:将求出的小规模问题的解合并成一个更大规模问题的解,自底向上的逐步求出原问题的解。
递归,学过数据结构的人对递归并不陌生,那么什么是递归呢?
直接或间接地调用自身的算法称为递归算法。
用函数自身来定义的函数为递归函数。
由分治法产生的子问题往往是原问题的较小规模,这就为使用递归技术而奠定了基础。在这种情况下反复应用分治法,可以使得子问题与原问题的类型一致,但规模却不断的在缩小,最终可以使子问题缩小到直接求出解为止,这自然就导致递归算法的产生。
下面来看看几个简单的递归样例。
【问题 1】阶乘函数
描述:从键盘输入正整数N(0<N<18),输出N!
分析:这是一个典型的递归程序,使用递归简单且易于理解,经过划分、求解、合并。
实现:
long f(int n)
{
if(n==0)
return 1;
else return n*f(n-1);
}
这个程序很简单,由此可以看出递归程序是有边界条件的,即子问题“要小到多小”才能直接求解。
再者就是原问题要逐步向子问题靠近,即原问题和子问题是何种递归关系。
【问题 2】Fibonacci 数列
描述:无穷数列1,1,2,3,5,8,13,21,34........称为Fibonacci数列。该数列看似平常,其实不然。
在现代物理、准晶体结构、化学等领域,斐波纳契数列都有直接的应用。
如果你看到有这样一个题目:
某人把一个8*8的方格切成四块,拼成一个5*13的长方形,故
作惊讶地问你:为什么64=65?其实就是利用了斐波那契数列的这个性质:5、8、13正是数列中相邻的三项。说得有点多了。
分析:斐波纳契数列以如下被以递归的方法定义:F0=0,F1=1,Fn=F(n-1)+F(n-2)(n>=2,n∈N*)。
实现:可以根据以上的数学定义,很容易用计算机程序将其表达。
【问题 3】排列问题
描述:设计一个递归算法生成n个元素的全排列。
分析: 设R={r1,r2,r3,...rn}是要进行排列的n个元素。
Ri=R-{ri}
集合Ri中的全排列记为Perm(Ri)
其中,riPerm(Ri)表示在全排列Perm(Ri)的每个排列前加上前缀ri得到的排列。
全排列问题可以归纳第一如下:
当n=1时,Perm(R)=r
当n>1时,Perm(R)由r1Perm(R1),r2Perm(R2).....rnPerm(Rn)构成。
实现:
#include<stdio.h>
//交换list[]中i与j两个元素
void Swap(int list[],int i,int j)
{
int t=list[i];
list[i]=list[j];
list[j]=t;
}
//对list中下标为k到n的元素进行全排列
void Perm(int list[],int k,int n)
{
if(k==n)
{
for(int i=0;i<=n;i++)
{
printf("%d ",list[i]);
}
putchar('\n');
}
else
{
for(int i=k;i<=n;i++)//k<m,list[k]与list[k,n]中的每个元素交换,递归计算list[k+1,n],并作为list[0,k]的后缀
{
Swap(list,k,i);
Perm(list,k+1,n);
Swap(list,k,i);
}
}
}
int main()
{
int arr[]={1,2,3,4,5,6};
Perm(arr,0,3);
return 0;
}
由于时间关系,本文就此结束。