栈与递归 递归与回溯 广义表

74
栈栈栈栈 栈栈栈栈 栈栈栈栈栈 栈栈栈栈栈 栈栈栈 栈栈栈

Upload: ivory

Post on 25-Jan-2016

156 views

Category:

Documents


13 download

DESCRIPTION

第五章 递归. 栈与递归 递归与回溯 广义表. 一、栈和递归. 递归定义 递归函数. 递归定义. 先定义最基本的概念 再用已定义的概念定义新的概念. 例 命题演算公式的定义 ( 1 ) 单个命题变元符号是命题 ( 2 ) 如果 A,B 是命题,则 (┐A), (A∧B), (A∨B), (A→B), ( A←→B) 都是公式. 递归定义. 先定义最基本的概念 再用已定义的概念定义新的概念. 例 标识符的定义 - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: 栈与递归 递归与回溯 广义表

栈与递归栈与递归 递归与回溯递归与回溯 广义表广义表

Page 2: 栈与递归 递归与回溯 广义表

一、栈和递归 递归定义 递归函数

Page 3: 栈与递归 递归与回溯 广义表

递归定义 先定义最基本的概念 再用已定义的概念定义新的概念

例 命题演算公式的定义 ( 1 ) 单个命题变元符号是命题 ( 2 ) 如果 A,B 是命题,则 (┐A), (A B), (A B),∧ ∨ (A→B), ( A←→B) 都是公式

Page 4: 栈与递归 递归与回溯 广义表

递归定义 先定义最基本的概念 再用已定义的概念定义新的概念例 标识符的定义 ( 1 )单个英文字母是标识符 ( 2 )标识符后缀一个数字 或一个英文字母是标识符

Page 5: 栈与递归 递归与回溯 广义表

递归函数的定义 一个算法可以分解成 若干相同的小算法 分解到某简单的子算法时终止

有一个或几个终止条件 递归:由其前面的值求当前值 递归必须导致终止条件

Page 6: 栈与递归 递归与回溯 广义表

递归函数的例例 函数 xn

x0=1

xn=x*xn-1 n>0

xn=xn-1/x n<0

例 函数 n! 0!=1

n!=n*(n-1)! n>0

Page 7: 栈与递归 递归与回溯 广义表

递归函数的例

函数 C(n, m)

C(0, m)=1, C(m, m)=1.

C(n, m)=C(n-1,m-1)+C(n, m-1)

Page 8: 栈与递归 递归与回溯 广义表

#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);}

Page 9: 栈与递归 递归与回溯 广义表

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; }}

Page 10: 栈与递归 递归与回溯 广义表

/*

<Run >Enter 4 positive integers: 0 7 1 4

0! = 1

7! = 5040

1! = 1

4! = 24

*/

Page 11: 栈与递归 递归与回溯 广义表

阶乘堆栈

主程序

参数4

4*Factorial(3)

参数3

3*Factorial(2)

参数2

2*Factorial(1)

参数1

1*Factorial(0)

参数0

Factorial(0) 1

1

2

6

24

Page 12: 栈与递归 递归与回溯 广义表

递归函数 先操作 后遍历 例 void Fucnc(char ch) { if(ch<=‘z’) { cout<<ch; Func(ch+1); } }

调用 Func(‘a’);输出 abcdefghijklmnopqrstuvwxyz

Page 13: 栈与递归 递归与回溯 广义表

递归函数 先遍历 后操作例 void Fucnc(char ch) { if(ch<=‘z’) { Func(ch+1); cout<<ch;} }

调用 Func(‘a’);输出 zyxwvutsrqponmlkjihgfedcba

Page 14: 栈与递归 递归与回溯 广义表

递归函数 操作 遍历 操作例 void Fucnc(char ch) { if(ch<=‘z’) { cout<<ch; Func(ch+1); cout<<ch;} }

调用 Func(‘a’);输出 abcdefghijklmnopqrstuvwxyz zyxwvutsrqponmlkjihgfedcba

Page 15: 栈与递归 递归与回溯 广义表

递归函数 遍历 操作 遍历例 void Fucnc(char ch) { if(ch<=‘d’) { Func(ch+1); cout<<ch; Func(ch+1); } }调用 Func(‘a’);输出 dcdbdcdadcdbdcd

Page 16: 栈与递归 递归与回溯 广义表

河内塔问题

A

B

C

Page 17: 栈与递归 递归与回溯 广义表

河内塔问题 将 A 塔上的金盘移到 B 塔上

!要求 一次只能移动一个盘 大盘不能压小盘

A

B

CA

Page 18: 栈与递归 递归与回溯 广义表

河内塔问题 第一次

A

B

C

Page 19: 栈与递归 递归与回溯 广义表

河内塔问题 第二次

A

B

C

Page 20: 栈与递归 递归与回溯 广义表

河内塔问题 第三次

A

B

C

Page 21: 栈与递归 递归与回溯 广义表

河内塔问题 第四次

A

B

C

Page 22: 栈与递归 递归与回溯 广义表

河内塔问题 第五次

A

B

C

Page 23: 栈与递归 递归与回溯 广义表

河内塔问题 第六次

A

B

C

Page 24: 栈与递归 递归与回溯 广义表

河内塔问题 第七次

A

B

C

Page 25: 栈与递归 递归与回溯 广义表

河内塔问题设 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

Page 26: 栈与递归 递归与回溯 广义表

河内塔问题程序

#include <iostream.h>

#pragma hdrstop

#include "strclass.h"

// move n disks from startpeg to endpeg,

// using middlepeg as the intermediate peg

Page 27: 栈与递归 递归与回溯 广义表

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);

}

}

Page 28: 栈与递归 递归与回溯 广义表

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’);

}

Page 29: 栈与递归 递归与回溯 广义表

/* <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*/

Page 30: 栈与递归 递归与回溯 广义表

迷宫 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

回溯 此路不通,返回回溯 此路不通,返回回溯 此路不通,返回

回溯 此路不通,返回

Page 31: 栈与递归 递归与回溯 广义表

二、递归和回溯 迷宫算法 八皇后问题

Page 32: 栈与递归 递归与回溯 广义表

// 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;

};

Page 33: 栈与递归 递归与回溯 广义表

#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);};

Page 34: 栈与递归 递归与回溯 广义表

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( );}

Page 35: 栈与递归 递归与回溯 广义表

回溯法

一个变量控制递归用另一个变量来控制回溯出现特定情况时该变量取值 0 回溯

1 。全局变量2 。变量参数 引用变量,指针变量3 。函数返回值

Page 36: 栈与递归 递归与回溯 广义表

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;}

Page 37: 栈与递归 递归与回溯 广义表

#include <iostream.h>

#pragma hdrstop

#include "maze.h"

// include the maze class

Page 38: 栈与递归 递归与回溯 广义表

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;}

Page 39: 栈与递归 递归与回溯 广义表

//maze1.dat

60 2 03 5 60 0 4 0 0 00 0 07 0 07

4

3

5 7

2 6

1

Page 40: 栈与递归 递归与回溯 广义表

//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

Page 41: 栈与递归 递归与回溯 广义表

//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

Page 42: 栈与递归 递归与回溯 广义表

/* <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.*/

Page 43: 栈与递归 递归与回溯 广义表

4

3

5 7

2 6

1

0 0 0

0 0 0

0 0 0 0 0

0

0

迷宫的另一种模型

Page 44: 栈与递归 递归与回溯 广义表

迷宫的另一种模型

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

Page 45: 栈与递归 递归与回溯 广义表

八皇后问题

W

W W

两皇后在同一行或同一列或同一对角线上互相杀死

要求:一个棋盘上摆八个皇后,任意两个都不互相杀死

Page 46: 栈与递归 递归与回溯 广义表

皇后的表示 用二维数组表示 8*8 棋盘 皇后用棋盘上的格点表示

用坐标表示皇后的位置 (a, 4) (1, 4)

用一维数组表示皇后的位置 int q[9]; q[1]=4; 表示第一行第四列有一个皇后 q[4]=2; 表示第四行第二列有一个皇后

Page 47: 栈与递归 递归与回溯 广义表

两个皇后冲突的特征

(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] |

Page 48: 栈与递归 递归与回溯 广义表

三、广义表LS=(a1, a2,······,an)

长度 n

每个 ai 1≤i≤n 或是一个元素(原子),或是一个子广义表。a1 是表头 head, a2,······,an 是表尾。

用小写字母表示原子,大写字母表示广义表。

Page 49: 栈与递归 递归与回溯 广义表

广义表的例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,······))).

Page 50: 栈与递归 递归与回溯 广义表

广义表的存储

广义表的结点标志域 表头指针 表尾指针

tag=1 hp tp

表结点 1

标志域 原子域 表尾指针

tag=0 atom tp

表结点 2

Page 51: 栈与递归 递归与回溯 广义表

广义表结点类定义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

Page 52: 栈与递归 递归与回溯 广义表

广义表的链表表示

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 ^

Page 53: 栈与递归 递归与回溯 广义表

广义表结点类的补充定义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); };

Page 54: 栈与递归 递归与回溯 广义表

广义表结点类的实现

template <class T>GLNode<T>:: GLNode(const T& item, GLNode<T>*t=NUL

L) { tag=ATOM; atom=item; temp.tp=t; }

Page 55: 栈与递归 递归与回溯 广义表

template <class T>GLNode<T>::GLNode(GLNode *h,GLNode *t)

{

tag=LIST;

hp=h;

tp=t;

}

Page 56: 栈与递归 递归与回溯 广义表

template <class T>

T& GLNode<T>::GetValue( )

{if (tag==ATOM)

return atom;

else

cout<<“no value”;

return 0;

}

Page 57: 栈与递归 递归与回溯 广义表

template <class T>

GLNode* GLNode<T>:: Next( )

{ return tp;}

Page 58: 栈与递归 递归与回溯 广义表

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; }

Page 59: 栈与递归 递归与回溯 广义表

广义表类定义

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( );

Page 60: 栈与递归 递归与回溯 广义表

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);};

Page 61: 栈与递归 递归与回溯 广义表

template<class T>

Glist<T>::GList(const GList& list)

{

CopyList(list):

}

Page 62: 栈与递归 递归与回溯 广义表

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;

}

Page 63: 栈与递归 递归与回溯 广义表

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;

}

Page 64: 栈与递归 递归与回溯 广义表

template <class T>

void Glist<T>::FreeGLNode(GLNode<T> *p)

{

free p;

}

Page 65: 栈与递归 递归与回溯 广义表

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;

}

Page 66: 栈与递归 递归与回溯 广义表

template<class T>void Glist<T>:: ClearGList( ){ if(first->tag==LIST) ClearGList(first->hp); ClearList(first->tp); free(this);}

Page 67: 栈与递归 递归与回溯 广义表

template <class T>

Glist<T>::GList(void)

{ first=new GLNode<T>;

first->tag=LIST;

first->hp=NULL;

first->tp=NULL;

}

Page 68: 栈与递归 递归与回溯 广义表

template <class T>

Glist<T>::Glist(GLNode<T>*p)

{

first=p;

}

Page 69: 栈与递归 递归与回溯 广义表

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);

}

Page 70: 栈与递归 递归与回溯 广义表

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);

}

Page 71: 栈与递归 递归与回溯 广义表

template<class T>

Glist<T>:: ~GList(void)

{

ClearList( );

}

Page 72: 栈与递归 递归与回溯 广义表

广义表的深度 Depth(list)

1 list 为空表Depth(list)= 0 list 为原子 1+Max {Depth(ai)}; O.W.

Page 73: 栈与递归 递归与回溯 广义表

广义表深度 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;}

Page 74: 栈与递归 递归与回溯 广义表

int Depth(GList list)

{

return Depth(list->first);

}