递归(一)
递归的基本概念
▲一个函数调用其自身,就是递归
●求n!的递归函数
#include <iostream>
using namespace std;
int Factorial(int n)
{
if (n == 0)
return 1;
else
return n * Factorial(n - 1);
}
int main()
{
cout << Factorial(3) << endl;
return 0;
}
结果:6
递归和普通函数调用一样是通过栈实现的
●汉诺塔问题
有三根杆子A,B,C。A杆上有N个(N>1)穿孔圆盘,盘的尺寸由下到上依次变小。要求按下列规则将所有圆盘移至C杆: 每次只能移动一个圆盘;大盘不能叠在小盘上面。 提示:可将圆盘临时置于B杆,也可将从A杆移出的圆盘重新移回A杆,但都必须遵循上述两条规则。问:如何移?最少要移动多少次?
汉诺塔示意图如下:
三个盘的移动:
解法:
解法的基本思想是递归。假设有A、B、C三个塔,A塔有N块盘,目标是把这些盘全部移到C塔。那么先把A塔顶部的N-1块盘移动到B塔,再把A塔剩下的大盘移到C,最后把B塔的N-1块盘移到C。每次移动多于一块盘时,则再次使用上述算法来移动。
输入
输入为一个整数后面跟三个单字符字符串。 整数为盘子的数目,后三个字符表示三个杆子的编号
输出
输出每一步移动盘子的记录。一次移动一行。 每次移动的记录为例如3:a->b 的形式,即把编号为3的盘子从a杆移至b杆。我们约定圆盘从小到大编号为1, 2, …n。即最上面那个最小的圆盘编号为1,最下面最大的圆盘编号为n。
样例输入
3 a b c
样例输出
1:a->c
2:a->b
1:c->b
3:a->c
1:b->a
2:b->c
1:a->c
#include <iostream>
using namespace std;
void Hanoi(int n, char src, char mid, char dest,int src_n)
{ //将src座上的n个盘子,以mid座位中转,移动到dest座
//题目要求输出前有盘子编号 令src座上最上方盘子编号是src_n
if (n == 1)//当只有一个盘子的时候
{
//直接将这一个盘子从src移动到dest即可
cout << src_n << ":" << src << "->" << dest << endl;
return;
}
Hanoi(n - 1, src, dest, mid, src_n);//先将n-1个盘子从src移动到mid
cout << src_n + n - 1 << ":" << src << "->" << dest << endl;
//再将一个盘子从src移动到dest
Hanoi(n - 1, mid, src, dest, src_n);//最后将这n-1个盘子从mid移动到dest
return;
}
int main()
{
char a, b, c;
int n;
cin >> n >> a >> b >> c;
Hanoi(n, a, b, c, 1);
return 0;
}
递归的作用
- 替代多重循环
- 解决本来就是用递归形式定义的问题
- 将问题分解为规模更小的子问题进行求解 …
●N皇后问题
用递归替代多重循环
n皇后问题:输入整数n,要求n个国际象棋的皇后,摆在n*n的棋盘上,互相不能攻击,输出全部方案。
八皇后问题:八重循环。n皇后,n重循环?
递归解决!!!
【问题描述】
输入一个正整数N,则程序输出N皇后问题的全部摆法。输出结果里面的每一行都代表一种摆法。行里的第i个数字如果是n,就代表第i行的皇后应该放在第n列。皇后的行、列编号都是从1开始算。
样例输入:
4
样例输出:
2 4 1 3
3 1 4 2
#include <iostream>
#include <cmath>
using namespace std;
int N;
int queenPos[100];
//用来存放算好的皇后位置 最左上角是(0,0)
void NQueen(int k)
{
//在0~k-1行的皇后已经摆好的情况下,摆第k行及其后的皇后
int i;
if (k == N)//k个皇后已经摆好
{
for (i = 0; i < N; i++)
cout << queenPos[i] + 1 << " ";//+1时候是因为列号行号都从1开始
cout << endl;
return;
}
for (i = 0; i < N; i++)//逐个尝试第k个皇后的位置
{
int j;
for (j = 0; j < k; j++)
{
//和已经摆好的k个皇后的位置比较,看是否冲突
if (queenPos[j] == i || abs(queenPos[j] - i) == abs(k - j))
{
break; //冲突,则试下一个位置
}
}
if (j == k)//当前选的位置i不冲突
{
queenPos[k] = i;//将第k个皇后摆放在位置i
NQueen(k + 1);
}
}//for(i=0;i<N;i++)
}
int main()
{
cin >> N;
NQueen(0);//从第0行开始摆皇后
return 0;
}
●逆波兰表达式
用递归解决递归形式的问题
- 一个数是一个逆波兰表达式,值为该数
- “运算符 逆波兰表达式 逆波兰表达式”是逆波兰表达式,值为两个逆波兰表达式的值运算的结果
- 一般教科书上将本题中的“逆波兰表达式”称为“波兰表达式”,而将运算符后置的表达式称为“逆波兰表达式”
逆波兰表达式是一种把运算法前置的算术表达式,例如普通的表达式2 + 3的逆波兰表达式表示法为+ 2 3。逆波兰表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如(2 + 3) x 4的逆波兰表示法为 x + 2 3 4。本题求解逆波兰表达式的值,其中运算符包括 + - * /四个。
输入
输入为一行,其中运算符和运算数之间都用空格分割,运算数是浮点数
输出
输出为一行,表达式的值
样例输入
例: * + 11.0 12.0 + 24.0 35.0
样例输出
1357.000000
提示:(11.0+12.0)x(24.0+35.0)
#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
double exp()
{
//读入一个逆波兰表达式,并计算其值
char s[20];
cin >> s;
switch (s[0])
{
case '+': return exp() + exp();
case '-': return exp() - exp();
case '*': return exp() * exp();
case '/': return exp() / exp();
default: return atof(s);//将字符串转化为浮点数
break;
}
}
int main()
{
printf("%lf", exp());
return 0;
}
下一篇链接: