1、递归(Recurve)的概念 迷宫(Maze)问题 递归过程与递归工作栈 广义表 (General Lists ),第五章 递归,递归的概念,递归的定义 若一个对象部分地包含它自己, 或用它自己给自己定义, 则称这个对象是递归的;若一个过程直接地或间接地调用自己, 则称这个过程是递归的过程。 在以下三种情况下,常常用到递归方法。定义是递归的数据结构是递归的问题的解法是递归的,定义是递归的,求解阶乘函数的递归算法long Factorial ( long n ) if ( n = 0 ) return 1;else return n*Factorial (n-1); ,例如,阶乘函数,求解阶乘
2、n! 的过程,计算斐波那契数列的函数Fib(n)的定义,求解斐波那契数列的递归算法long Fib ( long n ) if ( n = 1 ) return n; else return Fib (n-1) + Fib (n-2); ,数据结构是递归的,搜索链表最后一个结点并打印其数值 template void Find ( ListNode *f ) if ( f link = NULL )cout f data endl;else Find ( f link ); ,例如,单链表结构,在链表中寻找等于给定值的结点 并打印其数值 template void Print ( ListNo
3、de *f ) if ( f != NULL) if ( f data = x ) cout fdata endl; else Print ( flink ); ,问题的解法是递归的例如,汉诺塔(Tower of Hanoi)问题,#include #include “strclass.h” void Hanoi (int n, String A, String B, String C ) /解决汉诺塔问题的算法if ( n = 1 ) cout “ move “ A “ to ” C endl; else Hanoi ( n-1, A, C, B ); cout “ move “ A “ t
4、o “ C endl; Hanoi ( n-1, B, A, C ); ,迷宫问题,小型迷宫,路口 动作 结果1 (入口) 正向走 进到 22 左拐弯 进到 33 右拐弯 进到 44 (堵死) 回溯 退到 33 (堵死) 回溯 退到 22 正向走 进到 55 (堵死) 回溯 退到 22 右拐弯 进到 66 左拐弯 进到 7 (出口),43,521,76,6 左 0 直 2 右 0 行 3 行 5 行 60 0 40 0 00 0 07 0 07,小型迷宫的数据,迷宫的类定义#include #include #include class Maze private:int MazeSize; i
5、nt EXIT; Intersection *intsec; public:Maze ( char *filename );int TraverseMaze ( int CurrentPos ); ,交通路口结构定义struct Intersection int left; int forward;int right; ,Maze:Maze ( char *filename ) /构造函数:从文件 filename 中读取各路口/和出口的数据 ifstream fin; fin.open ( filename, ios:in | ios:nocreate ); /为输入打开文件,文件不存在则打
6、开失败 if ( !fin ) cout MazeSize; /输入迷宫路口数,intsec = new IntersectionMazeSize+1; /创建迷宫路口数组for ( int i=1; iintseci.left intseci.forward intseci.right; fin EXIT; /输入迷宫出口fin.close ( ); 迷宫漫游与求解算法 int Maze:TraverseMaze ( int CurrentPos ) if ( CurrentPos 0 ) /路口从 1 开始,if ( CurrentPos = EXIT ) /出口处理 cout Curre
7、ntPos “ “; return 1; else /递归向左搜寻可行if (TraverseMaze(intsecCurrentPos.left ) cout CurrentPos “ ”; return 1; else /递归向前搜寻可行if (TraverseMaze(intsecCurrentPos.forward) cout CurrentPos “ ”; return 1; else /递归向右搜寻可行if (TraverseMaze(intsecCurrentPos.right) cout CurrentPos “ “; return 1; return 0; ,递归过程与递归工
8、作栈,递归过程在实现时,需要自己调用自己。 每一次递归调用时,需要为过程中使用的参数、局部变量等另外分配存储空间。 层层向下递归,退出时的次序正好相反:递归次序n! (n-1)! (n-2)! 1! 0!=1返回次序 因此,每层递归调用需分配的空间形成递归工作记录,按后进先出的栈组织。,函数递归时的活动记录,long Factorial ( long n ) int temp;if ( n = 0 ) return 1;else temp = n * Factorial (n-1);RetLoc2return temp;,void main ( ) int n;n = Factorial (4
9、);RetLoc1,计算Factorial时活动记录的内容,调用次数 NumCall(k) = 2*Fib(k+1) - 1。,斐波那契数列的递归调用树,打印数组An的值void recfunc ( int A , int n ) if ( n = 0 ) cout An “ “; n-;recfunc ( A, n ); ,25 36 72 18 99 49 54 63 81,void iterfunc ( int A , int n ) /消除了尾递归的非递归函数while ( n = 0 ) cout “value “ An endl;n-; ,广义表 (General Lists ),
10、广义表的概念 n ( 0 )个表元素组成的有限序列,记作LS = (a0, a1, a2, , an-1)LS是表名,ai是表元素,它可以是表(称为子表),可以是数据元素(称为原子)。n为表的长度。n = 0 的广义表为空表。n 0时,表的第一个表元素称为广义表的表头(head),除此之外,其它表元素组成的表称为广义表的表尾(tail)。,广义表的特性,有次序性 有长度 有深度,可递归 可共享,A = ( ) B = ( 6, 2 ) C = ( a, ( 5, 3, x ) ) D = ( B, C, A ) E = ( B, D ) F = ( 4, F ),各种广义表的示意图,广义表的表
11、示,只包括整数和字符型数据的广义表链表表示,表中套表情形下的广义表链表表示,广义表结点定义,标志域 utype, 表明结点类型。0为表头结点,1 为整型原子结点,2为字符型原子结点,3为子表结点。 值域 value。当 utype = 0 时为表引用计数,= 1时为整数值,= 2 时为字符值, = 3 时为指向子表的表头结点的指针。 尾指针域 tlink。当 utype = 0 时为指向该表表头元素的指针;当 utype 0 时为指向同一层下一个表结点的指针。,utype = 0/1/2/3,value = ref /intgrinfo /charinfo / hlink,tlink,广义表的
12、带表头结点的存储表示,广义表的类定义,#define HEAD 0 #define INTGR 1 #define CH 2 #define LST 3 class GenList;class GenListNode friend class Genlist; private:int utype;GenListNode * tlink;,union int ref; /utype = 0,表头结点 int intgrinfo; /utype = 1, 整型 char charinfo; /utype = 2, 字符型GenListNode *hlink; /utype = 3,子表结点 val
13、ue; public:GenListNode ,class GenList private:GenListNode *first;GenListNode* GenList:Copy ( GenListNode*ls );int depth ( GenListNode *ls ); int equal ( GenListNode *s, GenListNode *t ); void GenList:Remove (GenListNode *ls ); public:Genlist ( ); GenList ( );GenListNode ,GenListNode *First ( ); GenL
14、istNode * Next ( GenListNode *elem );void Push ( GenListNode ,广义表的访问算法,广义表结点类的存取成员函数GenListNode ,void GenListNode:setInfo(GenListNode *elem,GenListNode /仅建立表头结点 ,GenListNode ,void GenList:Push ( GenListNode ,GenList ,广义表的递归算法,广义表的复制算法void GenList:Copy ( const GenList /复制 utype,switch ( lsutype ) cas
15、e HEAD : qref = lsref; break; case INTGR : qintgrinfo = lsintgrinfo;break; case CH : qcharinfo = lscharinfo;break; case LST : qhlink = Copy ( lshlink );break; qtlink = Copy ( lstlink ); return q; ,图5.16 广义表ls的链表结构,递归顺序 s0tlink s1hlink t0tlink t1tlink t2tlink NULL 回退 t2 回退t1回退 t0回退 s1tlink s2hlinku0t
16、link u1hlink v0tlink v1tlinkv2tlink NULL 回退 v2 回退 v1 回退v0 回退 u1tlink u2tlink NULL 回退u2 回退 u1 回退 u0 回退 s2tlinkNULL 回退 s2 回退 s1回退 s0 回退,求广义表的深度,例如,对于广义表E ( B (a, b), D ( B (a, b), C (u, (x, y, z), A ( ) ) ) 按递归算法分析:Depth (E) = 1+Max Depth (B), Depth (D) Depth (B) = 1+Max Depth (a), Depth (b) = 1Depth
17、(D) = 1+Max Depth (B), Depth (C),Depth (A),Depth (C) = 1+Max Depth (u), Depth (x, y, z) Depth (A) = 1Depth (u) = 0Depth (x, y, z) = 1+Max Depth (x), Depth (y), Depth (z) = 1 Depth (C) = 1+Max Depth (u), Depth (x, y, z) = 1+Max 0, 1 = 2 Depth (D) = 1+Max Depth (B), Depth (C),Depth (A) = 1+Max 1, 2, 1
18、 = 3Depth (E) = 1+Max Depth (B), Depth (D) = 1+Max 1, 3 = 4,E ( B (a, b), D ( B (a, b), C (u, (x, y, z), A ( ) ) ),int GenList:depth ( GenListNode *ls ) if ( lstlink = NULL ) return 1; /空表GenListNode *temp = lstlink; int m = 0;while ( temp != NULL ) /横扫广义表if ( temputype = LST ) /子表深度int n = depth (
19、temphlink ); if ( m n ) m = n; /不是子表不加深度temp = temptlink; return m+1; ,int GenList:depth ( ) return depth ( first ); ,广义表的删除算法,删除x前的广义表链表结构,扫描子链表若结点数据为x, 删除。可能做循环连续删。若结点数据不为x,不执行删除。若结点为子表,递归在子表执行删除。,void delvalue (GenListNode * ls, const value x) /在广义表中删除所有含x的结点if ( lstlink != NULL ) GenListNode * p
20、 = lstlink; /横扫链表while ( p != NULL / p指向同层下一结点/链表检测完或遇到子表或走到子表表/头结点或不是含x结点, 转出循环,if ( p != NULL ) if ( putype = LST ) /到子表中删除delvalue ( phlink, x ); delvalue ( p, x ); /向后递归删除 GenList:GenList ( ) /析构函数 Remove ( first ); ,void GenList:Remove (GenListNode *ls ) lsref -; /引用计数减一if ( !lsref ) /引用计数减至0才能
21、删除 GenListNode *y = ls; while ( ytlink != NULL ) /横扫链表y = ytlink;if ( yutype = LST ) /遇到子表Remove ( yhlink ); /递归删除 ytlink = av; av = ls;/扫描完后,回收到可利用空间表 ,从字符串s建立广义表的链表表示lsint Genlist: CreateList ( GenListNode *ls, char * s ) char *sub, *hsub; int tag;ls = new GenListNode ( ); /建立表头结点lsutype = HEAD; l
22、sref = 1;if ( strlen (s) = 0 | !strcmp ( s,“( )“ ) )lstlink = NULL; /空表 else strncpy ( sub, s+1, strlen (s)-2 );/脱去广义表外面的引号GenListNode* p = ls;,while ( strlen (sub) != 0 ) /建立表结点p = ptlink = new GenListNode ( );/创建新结点,向表尾链接if ( sever ( sub, hsub ) ) /以逗号为界,分离第一个表元素hsubif ( hsub0 != ( elseif ( hsub0
23、!= ( & hsub0 = ) /非子表且是字符分界符,putype = CH; pcharinfo = hsub; else /是子表,递归建立子表putype = LST; CreateList ( phlink, hsub );else return 0; /字符串表达式有错 /循环完成ptlink = NULL; /封闭最后一个结点return 1; ,int Genlist:sever ( char *str1, char *hstr1 ) /对不含外分界符的字符串分离第一个元素char ch = str10; int n = strlen ( str1 );int i = 0,
24、k = 0;/检测str1,扫描完或遇到, 且括号配对则停while ( i n ,if ( i n ) strncpy ( hstr1, str1, i-2 );/str1的前i-2个字符传送到hstr1strncpy ( str1, str1+i-1, n-i+1 );/后n-i+1个字符留在str1, 滤去,return 1;else if ( k != 0 ) return 0; /括号不配对出错else /括号配对strcpy ( hstr1, str1 ); str1 = 0;/str1全部传送给hstr1return 1; ,设 str = ( ( 2, ( b, 7 ) ), ( ), ( d ) ),得到的广义表链表结构,