递归
递归算法就是通过解决同一问题的一个或多个更小的实例来最终解决一个大问题的算法。
递归函数就是能调用自身的函数。
递归算法是递归定义的函数。
递归的深度就是计算过程中嵌套函数调用的最大程度。
递归函数满足下面两个基本属性:
1.必须明确的解决归纳基础。
2.每一次递归调用,必须包括更小的参数值。
递归举例:链表求逆
void traverseR(link h,void(*visit)(link))
{
if (h == NULL)//递归结束条件
return;
(*visit)(h);//函数指针进行访问节点
traverse(h->next,visit);//尾递归,进行下一个节点访问
}
分治法
在许多递归程序中使用两个递归调用,每个递归调用约处理输入一半的信息,这就是分治法的范型。
分治法程序举例:
将数组a[l],...a[r]分成a[l],...a[m]和a[m+1],...,a[r]两部分,分别递归的求出每一部分的最大元素。
Item max(Item a[],int l,int r)
{
Item u,v;
int m=(l+r)/2;
if(l==r)//仅剩一个,不能再分左右,则递归结束。
return a[l];
u=max(a,l,m);//递归的求左半最大
v=max(a,m+1,r);//递归的求右半最大
if(u>v)//取出左右部分中最大值
return u;
}
else return v;
动态规划
自底向上动态规划:
按以最小开始的顺序计算函数值,在每一步使用前已经计算出的值来计算当前值。(预先计算这些值)
计算斐波那契:
F[0] = 0;
F[1] = 1;
for(i = 2;i <= N;i++)
{
F[i] = F[i-1] + F[i-2];
}
自顶向下动态规划:
实现递归程序来存储它所计算的每一个值,并通过检查所存储的值,来避免重新计算它们的任何项。(存储已知值)
int F(int i)
{
int i;
if(knowF[i] != unknow)
return knowF[i];
if(i == 0) t=0;
if(i == 1) t=1;
if(i >1) t = F(i-1) + F(i-2);
return knowF[i] = t;
}
通常选择自顶向下而不是自底向上动态规划,原因如下:
- 自顶向下动态规划是一个自然的求解问题的机械转化。
- 计算子问题的顺序能自己处理。
- 我们可能不需要计算所有子问题的解。
注意:
当我们需要的可能函数值的数目太大以至于不能存储(自顶向下)或预先计算(自底向上),动态规划就好变的低效。