递归的入门介绍
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了递归的入门介绍相关的知识,希望对你有一定的参考价值。
这是一只海龟,但小程要介绍的是递归。
递归是一种很重要的结构与设计思想。之所以重要,是因为读者经常会遇到递归结构,或递归算法。而为了解决某些问题,递归的设计思想有时很有效果。
本文介绍递归的设计与实现。
小程先介绍递归的表现,再介绍怎么理解递归、实现递归,最后再举一些使用递归算法的例子。
(一)递归的表现
有递,有归,才为递归。
日常生活中,有很多递归或不完整递归的表现。比如下面这些:
-
和尚讲故事
从前有座山,山里有座庙,庙里有个老和尚,老和尚给小和尚讲故事,讲的是从前有座山。。。。
-
沙滩是怎么形成的
A:沙堆是怎么形成的?
B:沙堆是一个沙堆加上一粒沙。
A:那这一个沙堆是怎么形成的?
B:这一个沙堆是一个沙堆加上一粒沙。
A:... -
吓得我
-
递归函数
f(x) = g(f(x-1))
-
巧妙的衣服
-
谣言成真,那还算造谣吗?
上海一男子因造谣称自己因造谣而被拘留15日而被拘留15日。
-
洋葱的构成
一个洋葱就是带着一层洋葱皮的洋葱。
- 转发通知
这些例子可以看到递归的影子,可以感受到递归的一个特点就是“嵌套”,一层套一层,层层新。
(二)理解递归
递归的表现是调用自己。
之所以能调用自己,是因为子问题也能用原问题的解决办法。
递归的设计,就是把问题分解成更小的问题,而且更小的问题也能用原问题的解决办法。在问题规模足够小的时候,把它解决掉,再层层返回,层层组合。
设计递归算法,需要能从大到小、从全局到局部地去想问题。
有时,先假设这个算法已经能解决此类问题,再让同构的问题大胆调用这个算法。
(三)实现递归
实现递归时,有几个要点可以考虑。
一是如何调用到自己,也就是如何让第二层调用到第一层。
二是在什么时候结束递归。
三是每一层递归返回时需要处理什么。
小程觉得,读者可以在实战中去参透这几个要点,或者总结出自己的要点(或技巧)。下面就举一些例子,并用递归的算法来实现。
(四)示例
这里,小程不考虑性能的问题,只展示怎么设计递归算法。
问题1:输入数字n,打印出1到n的所有数字。
主体:要打印1到n,那先打印1到n-1,再打印一个n就可以了。这个就是主体,只考虑n跟n-1。
结束:在n为1时打印并结束递归。
代码示例:
void pr(int n) {
if (n == 1) {
printf("1\n");
return;
}
pr(n-1);
printf("%d\n", n);
}
效果:
问题2:输出“我当然知道 我知道 我知道 我知道 ...我是个sb 这件事 这件事...这件事”,输入n来控制次数。
主体:把“我当然知道”放在递归函数外,因为它不符合同构的原则。先输出“我知道”,再递归到下一层即可。
结束:在递减到0时,结束递归。
收尾:在递归返回后,输出“这件事”。
代码示例:
#include <stdio.h>
void pr(int n) {
if (n == 0) {
printf("[我是sb]");
return;
}
printf("我知道[");
pr(n-1);
printf("这件事]");
}
int main(int argc, char *argv[])
{
printf("我当然知道{");
pr(10);
printf("}\n");
return 0;
}
效果:
问题3:求二叉树的高度(最长路径)。
主体:左子树与右子树的高度的最大值,加1就是当前树的高度。
结束:没有子树了。
代码示例:
int treeHeight(struct TreeNode* root) {
if (!root) return 0;
int left = treeHeight(root->left);
int right = treeHeight(root->right);
return MAX(left, right) + 1;
}
问题4:求数组中的最大值与最小值。
演示代码:
#include <iostream>
using namespace std;
template<typename T>
void max_min( T a[], int low, int high, T & max, T & min)
{
if ( low == high ) // 只有一个元素不再划分
{
max = min = a[low];
return;
}
else if ( low == high -1 ) // 只有两上元素不再划分
{
if ( a[low] < a[high] )
{
max = a[high];
min = a[low];
}
else
{
max = a[low];
min = a[high];
}
return;
}
int mid = (low + high) / 2;
T max_another;
T min_another;
max_min( a, low, mid, max, min );
max_min( a, mid+1, high, max_another, min_another );
if ( max < max_another )
max = max_another;
if ( min > min_another )
min = min_another;
}
int _tmain(int argc, _TCHAR* argv[])
{
double a[5] = {23.23, 23.45, .3, -89.3, -2.1};
double max, min;
max_min<double>( a, 0, 4, max, min );
cout << "max: " << max << " min: " << min << endl;
return 1;
}
最后,小程再提一下递归的深度。
每次递归调用都意味着部分数值压入栈中(比如系统维护的下压栈),这是跟迭代的区别。在迭代中每次循环结束时所有局部变量都获得释放,而递归却会不断累计,所以使用递归算法必须考虑它的深度,考虑是否会造成栈溢出,与及对效率造成的影响。
另外,每一次递归调用,问题的规模都应该有所减少,并最终达到终止条件的要求,从而结束递归调用。
至此,递归的入门介绍完毕了。
总结一下,本文介绍了递归的表现、递归的理解与设计,最后举了几个例子并用递归的思路来实现。递归是一个重要的思考问题的思路,希望本文能帮到读者理解这种思路。
以上是关于递归的入门介绍的主要内容,如果未能解决你的问题,请参考以下文章