递归调用之汉诺塔问题/线性表总结

文章详细介绍了汉诺塔问题的解决方法,通过递归算法将问题分解为更小的部分,最终得出解题步骤。递归函数调用的过程类似于分治策略,从n个盘子到n-1个盘子,直到只剩一个盘子。同时,文章提到了时间复杂度为2^n,空间复杂度为O(n),并简要讨论了线性表的顺序表和链式表两种结构的优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

汉诺塔 是一个常见的简单递归问题

如果有三根柱子,分别为A,B,C;
A柱子上摆放着三个大小不同的圆盘,下面的比上面的要大。
每次只能移动一个圆盘,并不能使上面的圆盘比下面的大。
那么把A柱上的圆盘移动到C柱需要几步。

这就是汉诺塔的具体问题。
那么要解决这个问题 我们可以把这个过程分成三步。

1.首先把除了最底层的圆盘,其他都挪到B柱上。
2.然后把最底层的圆盘移动到C柱上。
3.最后把B柱的圆盘移动到C柱上。

那么根据上面的文字描述给出以下表达式(res(n)表示n个圆盘需要移动的次数):

res(n) = res(n - 1) + 1 + res(n - 1);

当然这样肯定没办法算出最终结果。我们需要给他一个初始值。

当n = 1(或0)时,res = 1(0)。
接下来就是完整的代码啦

#include<stdio.h>

/**
 * Hanoi.
 */
void hanoi(int paraN, char paraSource, char paraDestination, char paraTransit) {
	if (paraN <= 0) {
		return ;
	} else {
		hanoi(paraN - 1, paraSource, paraTransit, paraDestination);
		printf("%c -> %c \r\n", paraSource, paraDestination);
		hanoi(paraN - 1, paraTransit, paraDestination, paraSource);
	}//Of if
}//Of hanoi

/**
 * Test the hanoi function.
 */
void hanoiTest() {
	printf("---- addToTest begins. ----\r\n");

	printf("2 plates\r\n");
	hanoi(2, 'A', 'B', 'C');

	printf("3 plates\r\n");
	hanoi(3, 'A', 'B', 'C');

	printf("---- addToTest ends. ----\r\n");
}//Of addToTest

/**
 * The entrance.
 */
void main() {
	hanoiTest();
}//Of main.

下面是运行结果

---- addToTest begins. ----
2 plates
A -> C
A -> B
C -> B
3 plates
A -> B
A -> C
B -> C
A -> B
C -> A
C -> B
A -> B
---- addToTest ends. ----

汉诺塔问题具体分析
1.自顶向下,逐渐求精,函数调用:
自顶向下就是把整个大的问题逐步拆分成几个小问题,从最开始的条件分析,以汉诺塔为例,整个求次数可以划分成三步:
先把n-1个圆盘移到一个柱子上,然后把底盘移到C柱上,最后把n-1个圆盘移动到C柱上。这就是解决问题的元步骤,通过
函数三步的调用就能算出最终的结果。

2.递归与分治(基础与归纳)
每次都是在n个盘子的移动中调用n-1个盘子移动的函数,然后制定一个下界,之后就是函数自己调用一步步从n走到0,最后
给出我们想要的结果,通过对每个调用的函数的执行就是用的分治的思想。

3.不要跨层分析
简单的来说就是我们发现他总的规律,就不用想他具体要怎么执行,系统会自动帮你把后面的步骤做完。

4.形参与实参(代码跟踪)
形参指的是函数中参数列表里的那几个元素,而实参是调用函数时,赋值给形参的原来的参数,也就是说调用函数的时候把
实参的值赋值给形参,这两个参数不公用同一地址。

5.有意义、规范的标识符
标识符为了让你过几个月还能一眼就看懂什么意思,需要用小驼峰命名法,给变量一个明确意义的名字。

6.时间复杂度
T(n)=2*T(n-1)+1;最后得出Tn=2^n;

7.递归栈(代码跟踪)
每次编译器读到函数的时候就会把这个函数push进栈,然后执行完之后才会pop出栈,所以如果在一个函数内部读到另一个
函数就会先让另一个函数入栈,出栈,做完才轮到外面那一层函数。下面是汉诺塔的递归栈的代码跟踪。

3 plates
----The funtion of 3 plant is start.----
----The funtion of 2 plant is start.----
----The funtion of 1 plant is start.----
----The funtion of 0 plant is start.----
----The function of 0 plate is finish.----
A -> B
----The funtion of 0 plant is start.----
----The function of 0 plate is finish.----
----The function of 1 plate is finish.----
A -> C
----The funtion of 1 plant is start.----
----The funtion of 0 plant is start.----
----The function of 0 plate is finish.----
B -> C
----The funtion of 0 plant is start.----
----The function of 0 plate is finish.----
----The function of 1 plate is finish.----
----The function of 2 plate is finish.----
A -> B
----The funtion of 2 plant is start.----
----The funtion of 1 plant is start.----
----The funtion of 0 plant is start.----
----The function of 0 plate is finish.----
C -> A
----The funtion of 0 plant is start.----
----The function of 0 plate is finish.----
----The function of 1 plate is finish.----
C -> B
----The funtion of 1 plant is start.----
----The funtion of 0 plant is start.----
----The function of 0 plate is finish.----
A -> B
----The funtion of 0 plant is start.----
----The function of 0 plate is finish.----
----The function of 1 plate is finish.----
----The function of 2 plate is finish.----
----The function of 3 plate is finish.----
---- addToTest ends. ----

8.空间复杂度
根据上面递归栈的代码跟踪,我们会发现每次最多递归层数不会超过N层,也就是栈内使用到的空间最多只有N个空间。所以空间复杂度为O(n)。

线性表总结
线性表从逻辑结构上分为顺序表和链式表:
1.顺序表:
在内存中属于同一片空间,连在一起。
顺序表的优势:查找速度快。
顺序表的劣势:添加删除速度慢,表容量固定。
2.链式表
在内存中属于不同空间,没有连在一起。
链式表的优势:添加速度快,内存动态分配。
链式表的劣势:查找速度慢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值