栈与递归的实现(Hanoi塔问题等等)
函数中有直接或间接地调用自身函数的语句,这样的函数称为递归函数。递归函数用
得好,可简化编程工作。但函数自己调用自己,有可能造成死循环。为了避免死循环,要
做到两点:
(1) 降阶。递归函数虽然调用自身,但并不是简单地重复。它的实参值每次是不一样
的。一般逐渐减小,称为降阶。如教科书式(33)的Ackerman 函数,当m≠0 时,求
Ack(m,n)可由Ack(m-1,⋯)得到,Ack()函数的第1 个参数减小了。
(2) 有出口。即在某种条件下,不再进行递归调用。仍以教科书式(33)的Ackerman
函数为例,当m=0 时,Ack(0,n)=n+1,终止了递归调用。所以,递归函数总有条件语
句。m=0 的条件是由逐渐降阶形成的。如取Ack(m,n)函数的实参m=-1,即使通过降阶也
不会出现m=0 的情况,这就造成了死循环。
编译软件在遇到函数调用时,会将调用函数的实参、返回地址等信息存入软件自身所
带的栈中,再去运行被调函数。从被调函数返回时,再将调用函数的信息出栈,接着运行
调用函数。编译软件开辟的栈空间是有限的,当递归调用时,嵌套的层次往往很多,就有
可能使栈发生溢出现象,从而出现不可预料的后果。运行algo3-8.cpp 时,m、n 的取值就
不可过大。
// algo3-8.cpp 用递归调用求Ackerman(m,n)的值
#include<stdio.h>
int ack(int m,int n)
{
int z;
if(m==0)
z=n+1; // 出口
else if(n==0)
z=ack(m-1,1); // 对形参m降阶
else
z=ack(m-1,ack(m,n-1)); // 对形参m、n降阶
return z;
}
void main()
{
int m,n;
printf("Please input m,n:");
scanf("%d,%d",&m,&n);
printf("Ack(%d,%d)=%d\n",m,n,ack(m,n));
}
代码运行结果:
/*
Please input m,n:3,9
Ack(3,9)=4093
Press any key to continue */
// algo3-9.cpp 用递归函数求解迷宫问题(求出所有解)
#include"c1.h" // 根据《PASCAL程序设计》(郑启华编著)中的程序改编
#include"func3-1.cpp" // 定义墙元素值为0,可通过路径为-1,通过路径为足迹
void Try(PosType cur,int curstep)
{ // 由当前位置cur、当前步骤curstep试探下一点
int i;
PosType next; // 下一个位置
PosType direc[4]={{0,1},{1,0},{0,-1},{-1,0}}; // {行增量,列增量},移动方向,依次为东南西北
for(i=0;i<=3;i++) // 依次试探东南西北四个方向
{
next.x=cur.x+direc[i].x; // 根据移动方向,给下一位置赋值
next.y=cur.y+direc[i].y;
if(m[next.x][next.y]==-1) // 下一个位置是通路
{
m[next.x][next.y]=++curstep; // 将下一个位置设为足迹
if(next.x!=end.x||next.y!=end.y) // 没到终点
Try(next,curstep); // 由下一个位置继续试探(降阶递归调用,离终点更近)
else // 到终点
{
Print(); // 输出结果(出口,不再递归调用)
printf("\n");
}
m[next.x][next.y]=-1; // 恢复为通路,以便在另一个方向试探另一条路
curstep--; // 足迹也减1
}
}
}
void main()
{
Init(-1); // 初始化迷宫,通道值为-1
printf("此迷宫从入口到出口的路径如下:\n");
m[begin.x][begin.y]=1; // 入口的足迹为1
Try(begin,1); // 由第1步入口试探起
}
代码运行结果如下:
此迷宫从入口到出口有2 条路径。由入口(1 行1 列足迹1)处向4 个方向试探,只有2
个方向(东、南)是通路(-1)。首先朝东继续试探。足迹2~4 都只有1 个方向是通路,足
迹5 到达出口。输出路径且逐一恢复足迹为-1(通路)。恢复后的情况是除入口为1 外,迷
宫其它各点与初态相同,以便第2 条路径(由入口向南)继续试探。
// algo3-10.cpp Hanoi塔问题,调用算法3.5的程序
#include<stdio.h>
int c=0; // 全局变量,搬动次数
void move(char x,int n,char z)
{ // 第n个圆盘从塔座x搬到塔座z
printf("第%i步: 将%i号盘从%c移到%c\n",++c,n,x,z);
}
void hanoi(int n,char x,char y,char z) // 算法3.5
{ // 将塔座x上按直径由小到大且自上而下编号为1至n的n个圆盘
// 按规则搬到塔座z上。y可用作辅助塔座
if(n==1) // (出口)
move(x,1,z); // 将编号为1的圆盘从x移到z
else
{
hanoi(n-1,x,z,y); // 将x上编号为1至n-1的圆盘移到y,z作辅助塔(降阶递归调用)
move(x,n,z); // 将编号为n的圆盘从x移到z
hanoi(n-1,y,x,z); // 将y上编号为1至n-1的圆盘移到z,x作辅助塔(降阶递归调用)
}
}
void main()
{
int n;
printf("3个塔座为a、b、c,圆盘最初在a座,借助b座移到c座。请输入圆盘数:");
scanf("%d",&n);
hanoi(n,′a′,′b′,′c′);
}
代码运行结果如下:
/*
3个塔座为a、b、c,圆盘最初在a座,借助b座移到c座。请输入圆盘数:3
第1步: 将1号盘从a移到c
第2步: 将2号盘从a移到b
第3步: 将1号盘从c移到b
第4步: 将3号盘从a移到c
第5步: 将1号盘从b移到a
第6步: 将2号盘从b移到c
第7步: 将1号盘从a移到c
Press any key to continue */
栈与递归的实现(Hanoi塔问题等等)的更多相关文章
- Hanoi塔问题——递归
/////////////Hanoi塔问题///////#include<iostream>using namespace std;void hanoi(int i,char A,char ...
- 栈->栈与递归
文字简述 1.阶乘函数 2.2阶Fiibonacci数列 3.n阶Hanoi塔问题 代码实现 // // Created by lady on 19-4-3. // #include <stdi ...
- c++迭代递归实现汉诺塔(5种迭代方法满足你)
#include <iostream> //从A到C using namespace std; int n; void ready() { cout << "请输入汉 ...
- 经典递归算法研究:hanoi塔的理解与实现
关于hanoi塔的原理以及概念,请Google,访问不了去百度. 主要设计到C中程序设计中递归的实现: 主代码实现如下: void hanoi(int src, int dest, int tmp, ...
- (转)Hanoi塔问题分析
转自:http://shmilyaw-hotmail-com.iteye.com/blog/2077098 简介 关于Hanoi塔问题的分析,在网上的文章都写烂了.之所以打算写这篇文章,更多的是针对这 ...
- Python递归实现汉诺塔
Python递归实现汉诺塔: def f3(n,x,y,z): if(n==1): print(x,'--->',z) else: f3(n-1,x,z,y) print(x,'--->' ...
- 剑指offer_面试题5_从尾到头打印链表(栈和递归实现)
题目:输入一个链表的头结点,从尾到头反过来打印出每一个节点的值 考察 单链表操作.栈.递归等概念. 理解:要实现单链表的输出,那么就须要遍历.遍历的顺序是从头到尾.而节点输出的顺序是从尾到头.因此,先 ...
- 深度优先搜索入门:POJ1164城堡问题(递归、用栈模拟递归)
将问题的各状态之间的转移关系描述为一个图,则深度优先搜索遍历整个图的框架为:Dfs(v) {if( v 访问过)return;将v标记为访问过;对和v相邻的每个点u: Dfs(u);}int main ...
- UVA10410 TreeReconstruction 树重建 (dfs,bfs序的一些性质,以及用栈处理递归 )
题意,给你一颗树的bfs序和dfs序,结点编号小的优先历遍,问你可能的一种树形: 输出每个结点的子结点. 注意到以下事实: (1)dfs序中一个结点的子树结点一定是连续的. (2)bfs,dfs序中的 ...
随机推荐
- Educational Codeforces Round 47 (Rated for Div. 2) :A. Game Shopping
题目链接:http://codeforces.com/contest/1009/problem/A 解题心得: 题意就是给你两个数列c,a,你需要从c中选择一个子串从a头开始匹配,要求子串中的连续的前 ...
- Tensorflow的最佳实践
Tensorflow的最佳实践 1.变量管理 Tensorflow提供了变量管理机制,可直接通过变量的名字获取变量,无需通过传参数传递数据.方式如下: #以下为两种创建变量的方法 v=tf.get ...
- Android开发——Android系统启动以及APK安装、启动过程
0. 前言 从Android手机打开开关,到我们可以使用其中的app时,这个启动过程到底是怎么样的? 1. 系统上电 当给Android系统上电,在电源接通的瞬间,CPU内的寄存器和各引脚均会被 ...
- P2340 奶牛会展(状压dp)
P2340 奶牛会展 题目背景 奶牛想证明它们是聪明而风趣的.为此,贝西筹备了一个奶牛博览会,她已经对N 头奶牛进行 了面试,确定了每头奶牛的智商和情商. 题目描述 贝西有权选择让哪些奶牛参加展览.由 ...
- spring+springmvc+maven+mongodb
1.前言 最近项目开发使用到了spring+springmvc+maven+mongodb,项目中的框架是用springboot进项开发的,对于我们中级开发人员来说,有利有弊,好处呢是springbo ...
- javascript数据相关处理,序列化反序列化,数据编码与解码
对象序列化简而言之,将对象转为字符串.在数据的传输过程中,经常会使用到对象序列化. javascript中常用的对象序列化:JSON.stringify(); javascript中常用的对象反序列化 ...
- Qt HUD(平显)演示程序绿色版
把一个黑底白字的程序改成黑底绿字 上对比图,左侧是原本,右侧是仿造,有些地方比例还是有问题 其实这个程序没有啥技术含量,就是画 #include "mainwindow.h" #i ...
- python 正则表达式 (重点) re模块
京东的注册页面,打开页面我们就看到这些要求输入个人信息的提示.假如我们随意的在手机号码这一栏输入一个11111111111,它会提示我们格式有误.这个功能是怎么实现的呢?假如现在你用python写一段 ...
- TF-IDF与主题模型 - NLP学习(3-2)
分词(Tokenization) - NLP学习(1) N-grams模型.停顿词(stopwords)和标准化处理 - NLP学习(2) 文本向量化及词袋模型 - NLP学习(3-1) 在上一篇博文 ...
- winform构造函数和load事件
有些地方,有些代码写在构造函数里面运行不成功: 但是加在load事件里面运行成功: 有时候,反则反之.