北京大學C語言學習第11天

遞 歸(一)
信息科學技術學院《程序設計與算法》
3
遞歸的基本概念
 一個函數調用其自身,就是遞歸
 求n!的遞歸函數

int Factorial(int n)
{
if (n == 0)
return 1;
else
return n * Factorial(n - 1);
}
4
F(3)3->F(3)5->F(2)3->F(2)5->F(1)3->F(1)5-> F(0)3->F(0)4:返回1->
F(1)5:返回1*1->F(2)5:返回2*1-> F(3)5:返回3*2-> 函數執行結束
1. int Factorial(int n)
2. {
3. if (n == 0)
4. return 1;
5. return n * Factorial(n - 1);
}

遞歸和普通函數
調用一樣是通過
棧實現的
主程序 6
參數4 cout << Factorial(4)
參數3 4Factorial(3)
參數2 3
Factorial(2)
參數1 2Factorial(1)
參數0 1
Factorial(0) 1
1
2
6
24
例題:
漢諾塔問題
(Hanoi)

古代有一個梵塔,塔內有三個座A、B、C,A座上有64個盤子,盤子大小
不等,大的在下,小的在上(如圖)。有一個和尚想把這64個盤子從A座移
到C座,但每次只能允許移動一個盤子,並且在移動過程中,3個座上的盤子
始終保持大盤在下,小盤在上。在移動過程中可以利用B座,要求輸出移動
的步驟。
漢諾塔問題(Hanoi)
簡單的版本:

#include <iostream> 
using namespace std; 
void Hanoi(int n, char src,char mid,char dest) 
//將src座上的n個盤子,以mid座爲中轉,移動到dest座
{ 
if( n == 1) { //只需移動一個盤子
cout << src << "->" << dest << endl; 
//直接將盤子從src移動到dest即可
return ; //遞歸終止
} 
Hanoi(n-1,src,dest,mid); //先將n-1個盤子從src移動到mid 
cout << src << "->" << dest << endl; 
//再將一個盤子從src移動到dest 
Hanoi(n-1,mid,src,dest); //最後將n-1個盤子從mid移動到dest 
return ; 
}
int main() 
{ 
int n; 
cin >> n; //輸入盤子數目
Hanoi(n,'A','B','C'); 
return 0; 
} 

提交能通過的版本:

#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) { //只需移動一個盤子
cout << src_n << ":" << src << "->" << dest << endl; 
//直接將盤子從src移動到dest即可
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; 
} 

漢諾塔問題手工解法(三個盤子)
遞歸的作用

  1. 替代多重循環
  2. 解決本來就是用遞歸形式定義的問題
  3. 將問題分解爲規模更小的子問題進行求解

    15
    N皇后問題
    用遞歸替代多重循環
    n皇后問題:輸入整數n, 要求n個國際象棋的皇后,擺在
    nn的棋盤上,互相不能攻擊,輸出全部方案。
    17
    用遞歸替代多重循環
    n皇后問題:輸入整數n, 要求n個國際象棋的皇后,擺在
    n
    n的棋盤上,互相不能攻擊,輸出全部方案。
    八皇后問題:八重循環。n皇后,n重循環?
    18
    用遞歸替代多重循環
    n皇后問題:輸入整數n, 要求n個國際象棋的皇后,擺在
    n*n的棋盤上,互相不能攻擊,輸出全部方案。
    八皇后問題:八重循環。n皇后,n重循環?
    遞歸解決!
    19
    N皇后問題
    輸入一個正整數N,則程序輸出N皇后問題的全部擺法。
    輸出結果裏的每一行都代表一種擺法。行裏的第i個數字如
    果是n,就代表第i行的皇后應該放在第n列。
    皇后的行、列編號都是從1開始算。
    樣例輸入:
    4
    樣例輸出:
    2 4 1 3
    3 1 4 2 20
#include <iostream>
#include <cmath>
using namespace std;
int N;
int queenPos[100]; 
//用來存放算好的皇后位置。最左上角是(0,0)
void NQueen( int k);
int main()
{
cin >> N;
NQueen(0); //從第0行開始擺皇后
return 0;
}
21
void NQueen( int k) { //在0~k-1行皇后已經擺好的情況下,擺第k行及其後的皇后
int i;
if( k == N ) { // N 個皇后已經擺好
for( i = 0; i < N;i ++ )
cout << queenPos[i] + 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; //衝突,則試下一個位置
}
} 22
if( j == k ) { //當前選的位置 i 不衝突
queenPos[k] = i; //將第k個皇后擺放在位置 i
NQueen(k+1);
}
} //for( i = 0;i < N;i ++ ) 
}

23
逆波蘭表達式
用遞歸解決遞歸形式的問題
例題:逆波蘭表達式
逆波蘭表達式是一種把運算符前置的算術表達式(其實一般教科書上稱這種表
達式爲波蘭表達式) ,例如普通的表達式2 + 3的逆波蘭表示法爲+ 2 3。逆波蘭
表達式的優點是運算符之間不必有優先級關係,也不必用括號改變運算次序,例如
(2 + 3) * 4的逆波蘭表示法爲* + 2 3 4。本題求解逆波蘭表達式的值,其中運算符
包括+ - * /四個。
輸入
輸入爲一行,其中運算符和運算數之間都用空格分隔,運算數是浮點

輸出
輸出爲一行,表達式的值。
25
用遞歸解決遞歸形式的問題
樣例輸入

    • 11.0 12.0 + 24.0 35.0
      樣例輸出
      1357.000000
      提示:(11.0+12.0)*(24.0+35.0)
      26
      用遞歸解決遞歸形式的問題
      本題中“逆波蘭表達式”的定義:
  1. 一個數是一個逆波蘭表達式,值爲該數
  2. “運算符 逆波蘭表達式 逆波蘭表達式” 是逆波蘭表達
    式 ,值爲兩個逆波蘭表達式的值運算的結果
    一般教科書將本題中的“逆波蘭表達式”稱爲“波蘭表達式”,而將運
    算符後置的表達式成爲“逆波蘭表達式”
    27
#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;
}
}
28
int main()
{
printf("%lf",exp());
return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章