算法综合
递归思想
递归是一个比用 goto 稍微好点的下下策,不必要时最好不要使用!后者是因为破坏了结构化设计而遭到嫌弃,前者则是因为性能太低而遭到嫌弃。
为了验证递归的性能真的很低,我们可以设计一个实验。通过输出斐波那契数列(指定索引从 1 开始计算,第 1 位值为 1)的前 5 位,计算递归与迭代的性能差距。
迭代(假定参数合法):
C
int getFbncE_IT(int index)
{
if (index <= 2)
return 1;
int a = 1, b = 1;
for (int i = 3; i <= index; i++)
if (i % 2)
a += b;
else
b += a;
return index % 2 ? a : b;
}递归(假定参数合法):
C
int getFbncE_RE(int index)
{
if (index <= 2)
return 1;
return getFbncE_RE(index - 1) + getFbncE_RE(index - 2);
}我们一眼就看出来递归算法用的代码量很少,思路也很清晰简洁,但是在应用中,该函数会被调用非常多的次数,有股指数爆炸的味道了:
| 自变量 | 1 | 2 | 3 | 4 | 5 | |
|---|---|---|---|---|---|---|
| 函数调用次数 | 1 | 1 | 3 | 5 | 9 |
由于递归调用会建立函数的副本,所以在一些循环需求很大的场景下,使用递归会有可能出现硬件级错误。
那么什么时候用递归是比较合适的呢?下面来看一个例子:
C
// 用户输入不定长度的字符串,以 Sharp 符号为截止标识,要求逆序输出字符串。
void showReverse()
{
char a;
scanf("%c", &a);
if (a != '#')
showReverse();
if (a != '#')
printf("%c", a);
}如果不用递归,我们可能要依靠链表来解决不定长度的问题,大大增加了编写的难度。
那如何得到使用它的规律呢?哈哈,我也不知道。毕竟常人用迭代,神人用递归。
分治思想
当一个问题规模较大且不易求解的时候,就可以考虑将问题分成几个小的模块,逐一解决。
比如在查找中,用到分治思想的就有折半查找法:在一个有序序列中,指定最小值为 low、最大值为 high
KMP 算法
拓扑排序
线性顺序查找
在一组具有相同数据类型集合中找出关键字等于给定值K的数据元素,这个操作过程称为查找。通常情况下,查找算法的时间性能是以平均查找长度(ASL)来衡量的。
其中,