栈与递归 递归与回溯 广义表
DESCRIPTION
第五章 递归. 栈与递归 递归与回溯 广义表. 一、栈和递归. 递归定义 递归函数. 递归定义. 先定义最基本的概念 再用已定义的概念定义新的概念. 例 命题演算公式的定义 ( 1 ) 单个命题变元符号是命题 ( 2 ) 如果 A,B 是命题,则 (┐A), (A∧B), (A∨B), (A→B), ( A←→B) 都是公式. 递归定义. 先定义最基本的概念 再用已定义的概念定义新的概念. 例 标识符的定义 - PowerPoint PPT PresentationTRANSCRIPT
栈与递归栈与递归 递归与回溯递归与回溯 广义表广义表
一、栈和递归 递归定义 递归函数
递归定义 先定义最基本的概念 再用已定义的概念定义新的概念
例 命题演算公式的定义 ( 1 ) 单个命题变元符号是命题 ( 2 ) 如果 A,B 是命题,则 (┐A), (A B), (A B),∧ ∨ (A→B), ( A←→B) 都是公式
递归定义 先定义最基本的概念 再用已定义的概念定义新的概念例 标识符的定义 ( 1 )单个英文字母是标识符 ( 2 )标识符后缀一个数字 或一个英文字母是标识符
递归函数的定义 一个算法可以分解成 若干相同的小算法 分解到某简单的子算法时终止
有一个或几个终止条件 递归:由其前面的值求当前值 递归必须导致终止条件
递归函数的例例 函数 xn
x0=1
xn=x*xn-1 n>0
xn=xn-1/x n<0
例 函数 n! 0!=1
n!=n*(n-1)! n>0
递归函数的例
函数 C(n, m)
C(0, m)=1, C(m, m)=1.
C(n, m)=C(n-1,m-1)+C(n, m-1)
#include <iostream.h>// compute n! = n*(n-1)*(n-2)...(2)(1), 0!=1 recursively
long Factorial(long n){ // if n == 0, then 0! = 1; otherwise, n! = n*(n-1)!
if (n == 0) return 1; else return n * Factorial(n - 1);}
void main (void)
{ int i, n; // enter 4 positive integers and compute n! for each
cout << "Enter 4 positive integers: "; for (i = 0; i < 4; i++) { cin >> n; cout << n << "! = " << Factorial(n) << endl; }}
/*
<Run >Enter 4 positive integers: 0 7 1 4
0! = 1
7! = 5040
1! = 1
4! = 24
*/
阶乘堆栈
主程序
参数4
4*Factorial(3)
参数3
3*Factorial(2)
参数2
2*Factorial(1)
参数1
1*Factorial(0)
参数0
Factorial(0) 1
1
2
6
24
递归函数 先操作 后遍历 例 void Fucnc(char ch) { if(ch<=‘z’) { cout<<ch; Func(ch+1); } }
调用 Func(‘a’);输出 abcdefghijklmnopqrstuvwxyz
递归函数 先遍历 后操作例 void Fucnc(char ch) { if(ch<=‘z’) { Func(ch+1); cout<<ch;} }
调用 Func(‘a’);输出 zyxwvutsrqponmlkjihgfedcba
递归函数 操作 遍历 操作例 void Fucnc(char ch) { if(ch<=‘z’) { cout<<ch; Func(ch+1); cout<<ch;} }
调用 Func(‘a’);输出 abcdefghijklmnopqrstuvwxyz zyxwvutsrqponmlkjihgfedcba
递归函数 遍历 操作 遍历例 void Fucnc(char ch) { if(ch<=‘d’) { Func(ch+1); cout<<ch; Func(ch+1); } }调用 Func(‘a’);输出 dcdbdcdadcdbdcd
河内塔问题
A
B
C
河内塔问题 将 A 塔上的金盘移到 B 塔上
!要求 一次只能移动一个盘 大盘不能压小盘
A
B
CA
河内塔问题 第一次
A
B
C
河内塔问题 第二次
A
B
C
河内塔问题 第三次
A
B
C
河内塔问题 第四次
A
B
C
河内塔问题 第五次
A
B
C
河内塔问题 第六次
A
B
C
河内塔问题 第七次
A
B
C
河内塔问题设 n 个金盘移动 F(n) 次F(1)=1F(n)=F(n-1)+1+F(n-1)=2*F(n-1)+1
F(n)+1=2*(F(n-1)+1) =22*(F(n-2)+1) =······ =2n-1*(F(1)+1)=2n
F(n)=2n-1
河内塔问题程序
#include <iostream.h>
#pragma hdrstop
#include "strclass.h"
// move n disks from startpeg to endpeg,
// using middlepeg as the intermediate peg
void hanoi(int n, char A, char B, char C)
{ if (n == 1)
cout << “move ”<<A << " → " < B << endl;
else
{ hanoi(n-1,A, C, B);
cout << “move ”<<A << " → " << B << endl;
hanoi(n-1, C, B, A);
}
}
void main( )
{ int n; // number of disks and the peg names
cout << "Enter the number of disks: ";
cin >> n;
cout << "The solution for n = " << n << endl;
hanoi(n, ‘A’, ‘B’, ‘C’);
}
/* <Run 河内塔问题 >Enter the number of disks: 3The solution for n = 3move A → Bmove A → Cmove B → Cmove A → Bmove C → Amove C → Bmove B → C*/
迷宫 maze
struct Intersection
{int left;
int forword;
int right;
};
4
3
5
2
1
7
6
60 2 03 5 60 0 40 0 00 0 07 0 07
回溯 此路不通,返回回溯 此路不通,返回回溯 此路不通,返回
回溯 此路不通,返回
二、递归和回溯 迷宫算法 八皇后问题
// record that specifies the intersection you
// arrive at when departing left, forward or right
// from the current intersection
struct Intersection{
int left;
int forward;
int right;
};
#include <iostream.h>
#include <fstream.h>
#include <stdlib.h>
class Maze{ int mazesize;
int EXIT;
Intersection *intsec;
public:
Maze(char *filename);
int TraverseMaze(int intsecvalue);};
Maze::Maze(char *filename){ ifstream fin; int i; fin.open(filename, ios::in | ios::nocreate); if (!fin) { cerr << "The maze data file " << filename
<< " cannot be opened!" << endl; exit(1); }
fin >> mazesize; intsec = new Intersection[mazesize+1]; for (i = 1; i <= mazesize; i++) fin >> intsec[i].left >> intsec[i].forward >> intsec[i].right; fin >> EXIT; fin.close( );}
回溯法
一个变量控制递归用另一个变量来控制回溯出现特定情况时该变量取值 0 回溯
1 。全局变量2 。变量参数 引用变量,指针变量3 。函数返回值
int Maze::TraverseMaze(int intsecvalue){ if (intsecvalue > 0) {if (intsecvalue = = EXIT) { cout << intsecvalue << " "; return 1; } else if (TraverseMaze(intsec[intsecvalue].left)) { cout << intsecvalue << " "; return 1; } else if (TraverseMaze(intsec[intsecvalue].forwar
d)) {cout << intsecvalue << " "; return 1; } else if (TraverseMaze(intsec[intsecvalue].right)) { cout << intsecvalue << " "; return 1; } } return 0;}
#include <iostream.h>
#pragma hdrstop
#include "maze.h"
// include the maze class
void main (void){ char filename[32]; cout << "Enter the data file name: "; cin >> filename; Maze M(filename); if (M.TraverseMaze(1)) cout << "\nYou are free!" << endl; else cout << "No path out of the maze" << endl;}
//maze1.dat
60 2 03 5 60 0 4 0 0 00 0 07 0 07
4
3
5 7
2 6
1
//maze2.dat
11 0 2 03 0 50 0 40 0 06 7 00 0 08 0 09 0 00 11 100 0 00 0 012
10
11 9 8
7
4 6
3 2 5
1
//bigmaze.dat
18
0 2 0 3 8 0 7 4 0 0 6 5 0 0 0
0 0 0 0 0 0 9 0 0 0 0 10 14 0 11
12 13 0 0 0 0 0 0 0 0 15 16 0 0 0
17 0 0 0 18 19 0 0 0
19
/* <Run #1 >Enter the data file name: maze1.dat7 6 2 1You are free!<Run #2 >Enter the data file name: maze2.datNo path out of the maze<Run #3 >Enter the data file name: bigmaze.dat19 17 16 14 10 9 8 2 1You are free.*/
4
3
5 7
2 6
1
0 0 0
0 0 0
0 0 0 0 0
0
0
迷宫的另一种模型
迷宫的另一种模型
10
11 9 8
7
4 6
3 2 5
1
0
0
0 0 0
0
0 0 0
0 0 0
0 0 0 0 0 0 0
0
0
八皇后问题
W
W W
两皇后在同一行或同一列或同一对角线上互相杀死
要求:一个棋盘上摆八个皇后,任意两个都不互相杀死
皇后的表示 用二维数组表示 8*8 棋盘 皇后用棋盘上的格点表示
用坐标表示皇后的位置 (a, 4) (1, 4)
用一维数组表示皇后的位置 int q[9]; q[1]=4; 表示第一行第四列有一个皇后 q[4]=2; 表示第四行第二列有一个皇后
两个皇后冲突的特征
(a1, b1) 与 (a2, b2) 冲突 当且仅当 a1= b1 或 a2= b2 或 | a1- b1|=| a2- b2|
q[i] 与 q[j] 冲突 当且仅当 i= j 或 q[i]=q[j] 或 | i - j |=| q[i] - q[j] |
三、广义表LS=(a1, a2,······,an)
长度 n
每个 ai 1≤i≤n 或是一个元素(原子),或是一个子广义表。a1 是表头 head, a2,······,an 是表尾。
用小写字母表示原子,大写字母表示广义表。
广义表的例A=( ) 长度为 0 的空表。B=(e) 只有一个元素的表,长为 1 。C=(a,(b,c,d)) 长度为 2 的广义表,第二个 元素是长度为 3 的子表。D=(A,B,C) 长度为 3 的广义表,三个 元素都是长度为 3 的子表。 D=(( ),(e),(a,(b,c,d)))
E=(a,E) 递归定义的表。 E=(a,(a,(a,······))).
广义表的存储
广义表的结点标志域 表头指针 表尾指针
tag=1 hp tp
表结点 1
标志域 原子域 表尾指针
tag=0 atom tp
表结点 2
广义表结点类定义enum ElemTag{ATOM, LIST};template<class T>struct GLNode{ ElemTag tag; union { T atom; GLNode *hp; } GLNode *tp;};
tag=1 hp tp
表结点 1
tag=0 atom tp
表结点 2
广义表的链表表示
1 ^ ^A
1 ^B
0 e ^
C 1 ^
0 e 1 ^
0 a 0 b 0 c ^
D 1 ^
1 ^ 1 1 ^
E 1 ^
0 a 1 ^
广义表结点类的补充定义enum ElemTag{ATOM, LIST};template<class T>class GLNode{ ElemTag tag; union { T atom; GLNode *hp; } GLNode *tp; public: GLNode(const T& item, GLNode *t=NULL); GLNode(GLNode *h,GLNode *t); ElemTag GetType( ){return tag;} T& GetValue( ); GLNode* Next( ); Void SetValue(GLNode & x); };
广义表结点类的实现
template <class T>GLNode<T>:: GLNode(const T& item, GLNode<T>*t=NUL
L) { tag=ATOM; atom=item; temp.tp=t; }
template <class T>GLNode<T>::GLNode(GLNode *h,GLNode *t)
{
tag=LIST;
hp=h;
tp=t;
}
template <class T>
T& GLNode<T>::GetValue( )
{if (tag==ATOM)
return atom;
else
cout<<“no value”;
return 0;
}
template <class T>
GLNode* GLNode<T>:: Next( )
{ return tp;}
template <class T> Void GLNode<T>:: SetValue(GLNode & x){ tag=x.tag; tp=x.tp; if(tag==ATOM) atom=x.atom; else hp=x.hp; }
广义表类定义
template <class T>class GList{ GLNode<T> *first; GLNode<T> *GetNode(const T&item, Node<T> *t=NULL); GLNode<T> *GetNode(Node<T> *h=NULL, Node<T> *t=NULL); void FreeGLNode(GLNode<T> *p); void CopyList(const GList& list); void ClearGList( );
public: GList(void); Glist(GLNode<T>*p); Glist(GLNode<T>&x,Glist&list);
Glist(GList&head,Glist&tail); GList(const GList& list);
~GList(void); GLNode *First( ); GLNode& Head( ); GLNode *Tail( ); void Push(GLNode<T>&x);//add node x as head
void SetHead(GLNode<T>&x);//replace x to head
void SetTail(Glist&L);};
template<class T>
Glist<T>::GList(const GList& list)
{
CopyList(list):
}
template <class T>
GLNode<T> * Glist<T>:: GetNode(const T& item,
Node<T> *t=NULL)
{
GLNode<T> *p=new GLNode<T>;
p->tag=ATOM;
p->atom=item;
p->tp=t;
return p;
}
template <class T>
GLNode<T> * Glist<T>::GetNode(
Node<T> *h=NULL, Node<T> *t=NULL)
{
GLNode<T>*p=new GLNode<T>;
p->tag=LIST;
p->hp=h;
p->tp=t;
return p;
}
template <class T>
void Glist<T>::FreeGLNode(GLNode<T> *p)
{
free p;
}
template <class T>GLNode<T>* GList<T>::CopyList( const GList& list)
{GLNode<T>*p,*q; q=this;
if(list.first!=NULL)
{ p=new GLNode<T>; p->tag=list.first->tag;
if(p.->tag==ATOM) p->atom=list.first->atom;
elae p->hp=CopyList(list.first->hp);
p->tp=CopyList(list.first->tp);
this=p; q.ClearList( );
return p;
}
template<class T>void Glist<T>:: ClearGList( ){ if(first->tag==LIST) ClearGList(first->hp); ClearList(first->tp); free(this);}
template <class T>
Glist<T>::GList(void)
{ first=new GLNode<T>;
first->tag=LIST;
first->hp=NULL;
first->tp=NULL;
}
template <class T>
Glist<T>::Glist(GLNode<T>*p)
{
first=p;
}
template <class T>
Glist<T>::Glist(GLNode<T>&x,Glist&list)
{first=new GLNode<T>;
first->tag=LIST;
first->hp=new GLNode(x);
first->tp=CopyList(list);
}
template<class T>
Glist<T>::Glist(GList&head,Glist&tail)
{first=new GLNode<T>;
first->tag=LIST;
first->hp=CopyList(head);
fisrt->tp=CopyList(tail);
}
template<class T>
Glist<T>:: ~GList(void)
{
ClearList( );
}
广义表的深度 Depth(list)
1 list 为空表Depth(list)= 0 list 为原子 1+Max {Depth(ai)}; O.W.
广义表深度 Depth(list) 的算法int Depth(GLNode *p){if(p==NULL)return 1; if(p->tag==ATOM) return 0; GLNode *s; int dep; for(int max=0,s=p;s;s=s->tp) {if(s->tag==LIST)dep=Depth(s->hp); if(dep>max)max=dep;} return max+1;}
int Depth(GList list)
{
return Depth(list->first);
}