200 likes | 299 Views
第五章 递归与广义表. 掌握: 递归的概念:什么是递归,种类,及递归求解方法 递归过程的机制与利用递归工作栈实现递归的方法 利用递归解决问题的分治法和回溯法 广义表的定义及其实现方法 广义表的递归算法 了解: 迷宫问题的递归思路及利用栈实现的非递归解法. 一、递归的概念 —— 利用前面运算来求得答案的过程 —— 一个象部分地包含它自己,或是用它自己给自己定义 —— 一个过程直接地或间接地调用自己. 递归算法的一般形式: void p ( 参数表 ) { if (递归结束条件)可直接求解步骤; ----- 基本项
E N D
第五章 递归与广义表 • 掌握: • 递归的概念:什么是递归,种类,及递归求解方法 • 递归过程的机制与利用递归工作栈实现递归的方法 • 利用递归解决问题的分治法和回溯法 • 广义表的定义及其实现方法 • 广义表的递归算法 • 了解: • 迷宫问题的递归思路及利用栈实现的非递归解法
一、递归的概念 ——利用前面运算来求得答案的过程 ——一个象部分地包含它自己,或是用它自己给自己定义 ——一个过程直接地或间接地调用自己 递归算法的一般形式: void p (参数表) { if (递归结束条件)可直接求解步骤;-----基本项 else p(较小的参数);------归纳项 }
1, n=0 n*(n-1)!n>0 例:求n! = long Factorial(long n){ if (n==0) return 1; else return n*Factorial(n-1); } Factorial(4); 对于一个较为复杂的问题,如果能够分解成几个相对简单的 且解法相同或类似的子问题来求解——分治法
递归和递归工作栈 P98 在递归调用时,必须做好参数保存,参数传递工作 —— 利用递归工作栈来处理。 每进入一层递归,系统就要建立一个新的工作记录(进栈) 每退出一层递归,就要从递归工作栈退出工作记录(出栈) 例:斐波那契数列:从第三个数开始,每一个数等于它前面两个数之和。0、1、1、2、 3、 5、 8…… long Fib(long n) { if (n<=1) return n; else return Fib(n-1)+ Fib(n-2); } 用栈求解P100 - 101 S.Push(w); S.getTop( ); S.Pop( )
一般从递归过程改为非递归过程的方法是先根据递归算法一般从递归过程改为非递归过程的方法是先根据递归算法 画出程序流程图,然后建立循环结构。 long Fib(long n) { if (n<=1) return n; f0=0, f1=1; for (i=2; i<=n; i++) { f2 =f1 +f0; f0=f1; f1=f2; } return f2; } Fib(6) n=6 0、1、 1、 2、 3、 5、 8 递归调用语句只有一个,而且是放在最后——尾递归
回溯法(试探法) ——将问题的候选解按某一顺序逐一枚举和检验; 在回溯法中,放弃当前候选解,寻找下一个候选解的过程 叫做回溯 入 口 迷 宫 问 题 出口
广义表 广义表(Lists,又称列表)是线性表的推广(表中有表)。 广义表是n(n>=0)个元素a0,a1,a2,…,an-1的有限序列, 记作:LS=(a0,a1,…,an-1) LS是广义表的名字,其中ai或者是原子项,或者是一个子表 n为它的长度(即元素个数)。表中括号的重数称为表的深度。 其中第一个元素a0为表头,其后组成的表(a1,a2,…,an-1)称为表尾。 (用大写字母表示表名,小写字母表示原子元素) A() B(6,2) C( ‘a’ , ( 5, 3, ‘x’)) D((6,2), (‘a’,(5,3,’x’)), ( )) E((6,2), ((6,2),(‘a’,(5,3,’x’)), ( ))) F(4, (4(4(4)……)))) 3、3 ——D(B,C,A) 2,4 ——E(B,D) 2,无穷 ——F( 4, F)
广义表ls的存储结构: 标志域 值域 value 尾指针:指向下一个元素 =0 表头结点 ; =1 整型原子结点 ; =2 字符原子结点 ; =3 子表结点 ; 计数ref 标志域=0; 整数intinfo =1; 字符charinfo =2; 指针hlink =3; 广义表中所有表都带有一个表头结点 例:LS(5,(‘x’ ,’y’ ), ((‘x’)),2)
类声明定义: P111结点定义: class GenListNode { 数据成员int utype; GenListNode * tlink; union { int ref; 引用计数, 当utype=0 int intinfo; 当utype=1 char charinfo; 当utype=2 GenListNode * hlink; 当utype=3 } value; …… …… …… 例:Ls->utype Ls->tlink Ls->value.ref / Ls->value.intinfo / Ls->value.charinfo / Ls->value.hlink
A() B(6,2) C( ‘a’ , ( 5, 3, ‘x’)) D(B, C, A) (B, D) F( 4, F)
插入 void GenList::setNext ( GenListNode * elem1, GenListNode * elem2) { GenListNode *temp=elem2; while (temp->tlink !=NULL) temp=temp->tlink; ① temp->tlink = elem1->tlink; ② elem1->tlink=elem2; ③ if (elem2->utype ==0) elem2->value.ref++; ④ } elem1 …… ③ ② elem2 …… ▲ ④ ① temp
递归算法 P115 ( (a, b), ( (c, d), e )) 表 5.2 1、复制算法 if (lst!=NULL) { q=new GenListNode( ); //创建新结点q; q->utype=lst->utype; //先拷标志结点utype; switch (lst->utype) { //根据utype情况拷值域value. case 0 : q->value.ref=lst->value.ref ; break; case 1 : q->value.intinfo=lst->value.intinfo ; break; case 2 : q->value.charinfo=lst->value.charinfo; break; case 3 : q->value.hlink=copy(lst->value.hlink); ① break; } q->tlink = Copy(lst->tlink); ② //复制同下一结点; } q
2、求深度 P116 3、判断两个广义表 s,t 是否相等(结构,对应成员值) P117 if 空表-----相等,返回1; if 两个都是非空表且结点类型(utype)相同(两个表对应结点) { 1、原子结点------值: 类型(utype)为1------value.intinfo x=1 类型(utype)为2------ value.charinfo x=1 2、子表-----继续分情况判断(递归) 类型(utype)为3------x=equal(s->value.hlink, t->value.hlink) 如果x=1----继续比较同一层的下一个结点(递归) equal(s->tlink,t->tlink) } return 0; }
int equal ( GenListNode *s, GenListNode *t ) { if (s->tlink)==NULL && t->tlink==NULL) return 1; if (s->tlink)!=NULL && t->tlink!=NULL && s->tlink->utype= =t->tlink->utype) { if (s->tlink->utype= = 1) if (s->tlink->value.intinfo= =t->tlink-> value.intinfo) x=1; else x=0; else if (s->tlink->utype= = 2) if (s->tlink->value.charinfo= =t->tlink-> value.charinfo) x=1; else x=0; else if (s->tlink->utype= = 3) x=equal(s->tlink->value.hlink, s->tlink->value.hlink) ; if (x) return equal(s->tlink, t->tlink); } return 0; } S S …… t t ……
删除 1、如果原子结点:值域中数据是x-----删除, 继续。 2、如果原子结点:值域中数据不是x-----不删除 3、如果子表结点:则从子表的表头结点开始,继续递归。 4、继续同一层下一个结点。 void delvalue (GenListNode * ls, const value x) { if (ls->tlink!=NULL) { P=ls->tlink; while (p!=NULL &&((p->utype= =1 && p->value.intinfo= =x)|| (p->utype= =2 && p->value.charinfo= =x)) { ls->tlink = p->tlink; delete p; p=ls->tlink;} if (p!=NULL) { if ( p->utype= = 3) delvalue (p->value.hlink, x) ; delvalue( p ,x); } } } l s P …… ……
建立链表 从字符串str1中摘取广义表的第一个元素赋给hstr1,剩下的元素赋给str1. int Genlist :: sever(char * str1 , char * hstr1 ) { char ch=str1[0]; int n=strlen (str1);①int i=0, k=0; while (i<n && (ch!=‘,’ || k!=0 )) { if (ch= = ‘(‘ ) k++; else (ch= =‘)’ ) k - - ; i++; ch=str1[i]; } if (i<n) { strncpy (hstr1, str1,i-1); strncpy (str1, str1+i , n-i ); return 1; } else if (k!=0) return 0; else { strcpy (hstr1,str1); str1=0; return 1; } } str1 ‘ (2,(‘b’,7)), ( ), (‘d’) ’ ch=( ; n=20 ① 第一次循环:k=1; i=1; ch=2 第二次循环:k=1; i=2; ch= , 第三次循环:k=1; i=3; ch=( 第四次循环:k=2; i=4; ch= ’ 第五次循环:k=2; i=5; ch=b …… …… 第九次循环:k=2; i=9; ch= ) 第十次循环:k=1; i=10; ch= ) 第十一次循环:k=0; i=11; ch= , 第十二次循环: hstr1=‘ (2,(‘b’,7)) ’ ; str1=‘( ),(‘d’) ‘
ls= new GenListNode( ). ls->utype = 0 ; ls-> value.ref=0; if (strlen(s)= =0|| strcmp(s,”( )”)= =0 ) ls->tlink=NULL; else { p=ls; strncpy (sub , s+1, strlen (s) – 2);① while ( strlen(sub)!=0 ) { p=p->tlink= new GenListNode( ); ② if ( sever(sub,hsub)) ③ { if (hsub[0] !=‘(‘ && hsyb[0] !=‘’’ ) { ④ p->utype=1; p->value.intinfo= atoi(hsub); } else if (hsub[0] !=‘(‘ && hsub[0]= =‘’’ ) { ⑤ p->utype=2; p->value.charinfo=hsub[1]; } else { p->utype=3; GreateList (p->value.hlink,hsub); } ⑥ } else return 0; ⑦ } p->tlink=NULL; ⑧ }return 1; s=‘( (2,(‘b’,7)), ( ), (‘d’))’ ① sub=‘ (2,(‘b’,7)), ( ), (‘d’)’ ③ hsub=‘ (2,(‘b’,7)) ’ ; sub=‘( ),(‘d’) ‘ ②P ②P ls ⑥ls P
掌握: • 递归的概念:什么是递归,种类,及递归求解方法 • 递归过程的机制与利用递归工作栈实现递归的方法 • 利用递归解决问题的分治法和回溯法 • 广义表的定义及其实现方法 • 广义表的递归算法 • 了解: • 迷宫问题的递归思路及利用栈实现的非递归解法
习题 P121- P123: 5-2,5-5,5-6,5-7 附加:5-1,5-3,5-4,5-8