第五章2递归与广义表.docx
- 文档编号:7283429
- 上传时间:2023-01-22
- 格式:DOCX
- 页数:20
- 大小:47.74KB
第五章2递归与广义表.docx
《第五章2递归与广义表.docx》由会员分享,可在线阅读,更多相关《第五章2递归与广义表.docx(20页珍藏版)》请在冰豆网上搜索。
第五章2递归与广义表
第5章递归与广义表
5-1已知A[n]为整数数组,试写出实现下列运算的递归算法:
(1)求数组A中的最大整数。
(2)求n个整数的和。
(3)求n个整数的平均值。
【解答】
#include
int*Elements;//数组指针intArraySize;//数组尺寸
intCurrentSize;//当前已有数组元素个数public:
RecurveArray(intMaxSize=10):
ArraySize(MaxSize),Elements(newint[MaxSize]){}~RecurveArray(){delete[]Elements;}voidInputArray();//输入数组的内容intMaxKey(intn);//求最大值intSum(intn);//求数组元素之和
floatAverage(intn);//求数组元素的平均值
};
voidRecurveArray:
:
InputArray(){//输入数组的内容
cout<<"InputthenumberofArray:
\n";
for(inti=0;i
}
intRecurveArray:
:
MaxKey(intn){//递归求最大值
if(n==1)returnElements[0];
inttemp=MaxKey(n-1);
if(Elements[n-1]>temp)returnElements[n-1];
elsereturntemp;
}
intRecurveArray:
:
Sum(intn){//递归求数组之和
if(n==1)returnElements[0];
elsereturnElements[n-1]+Sum(n-1);
}
floatRecurveArray:
:
Average(intn){//递归求数组的平均值
if(n==1)return(float)Elements[0];
elsereturn((float)Elements[n-1]+(n-1)*Average(n-1))/n;
}
intmain(intargc,char*argv[]){intsize=-1;
cout<<"No.oftheElements:
";
while(size<1)cin>>size;
RecurveArrayra(size);
ra.InputArray();
cout<<"\nThemaxis:
"< cout<<"\nThesumis: "< cout<<"\ntheavris: "< return0; } 5-2已知Ackerman函数定义如下: (1)根据定义,写出它的递归求解算法; (2)利用栈,写出它的非递归求解算法。 【解答】 (1)已知函数本身是递归定义的,所以可以用递归算法来解决: unsignedakm(unsignedm,unsignedn){ if(m==0)returnn+1;//m==0 elseif(n==0)returnakm(m-1,1);//m>0,n==0 elsereturnakm(m-1,akm(m,n-1));//m>0,n>0 } (2)为了将递归算法改成非递归算法,首先改写原来的递归算法,将递归语句从 结构中独立出来: unsignedakm(unsignedm,unsignedn){ unsignedv; if(m==0)returnn+1;//m==0 if(n==0)returnakm(m-1,1);//m>0,n==0 v=akm(m,n-1));//m>0,n>0 returnakm(m-1,v); } 计算akm(2,1)的递归调用树如图所示: akm(2,1) akm=5 v=3 akm=5 akm(1,3) v=akm(2,0) v=4 akm=3 akm(0,4)=5 v=akm(1,2) akm(1,1) v=3 akm(0,3)=4 v=akm(1,1) akm(0,2)=3 v=akm(1,0) v=2 akm(0,2)=3 akm(0,1)=2 v=akm(1,0) v=2 akm(0,1)=2 vmvnvmvnvmvnvmvnvmvnvmvn 用到一个栈记忆每次递归调用时的实参值,每个结点两个域{vm,vn}。 对以上实例,栈的变化如下: 1001 2011111102 改akm(m-1,1)改akm(m-1,1)v=n+1=2改akm(m-1,v)改akm(m-1,v) v=n+1=3 212121212113 vmvnvmvnvmvnvmvnvmvnvmvn 111102 1001 12121203 1313131304 改akm(m-1,1)v=n+1=2改akm(m-1,v)改akm(m-1,v)改akm(m-1,v)栈空,返回v=5 v=n+1=3v=n+1=4v=n+1=5 相应算法如下 #include #include“stack.h” #definemaxSize3500; unsignedakm(unsignedm,unsignedn){ structnode{unsignedvm,vn;} stack w.vm=m;w.vn=n;st.Push(w); do{ while(st.GetTop().vm>0){//计算akm(m-1,akm(m,n-1)) while(st.GetTop().vn>0)//计算akm(m,n-1),直到akm(m,0) {w.vn--;st.Push(w);} w=st.GetTop();st.Pop();//计算akm(m-1,1) w.vm--;w.vn=1;st.Push(w); }//直到akm(0,akm(1,*)) w=st.GetTop();st.Pop();v=w.vn++;//计算v=akm(1,*)+1 if(st.IsEmpty()==0)//如果栈不空,改栈顶为(m-1,v) {w=st.GetTop();st.Pop();w.vm--;w.vn=v;st.Push(w);} }while(st.IsEmpty()==0); returnv; } 5-3【背包问题】设有一个背包可以放入的物品的重量为s,现有n件物品,重量分别为w[1],w[2],…,w[n]。 问能否从这n件物品中选择若干件放入此背包中,使得放入的重量之和正好为s。 如果存在一种符合上述要求的选择,则称此背包问题有解(或称其解为真);否则称此背包问题无解(或称其解为假)。 试用递归方法设计求解背包问题的算法。 (提示: 此背包问题的递归定义如下: ) 【解答】根据递归定义,可以写出递归的算法。 enumboolean{False,True} booleanKnap(ints,intn){ if(s==0)returnTrue; if(s<0||s>0&&n<1)returnFalse; if(Knap(s–W[n],n-1)==True) {cout< returnKnap(s,n-1); } 若设w={0,1,2,4,8,16,32},s=51,n=6。 则递归执行过程如下 递归 Knap(51,6) returnTrue,完成 Knap(51-32,5) returnTrue,打印32 Knap(19-16,4) returnTrue,打印16 Knap(3-8,3) returnFalse Knap(3,3) returnTrue,无动作 s=-5<0 returnFalse Knap(3-4,4) returnFalse Knap(3,2) returnTrue,无动作 s=-1<0 returnFalse Knap(3-2,1) returnTrue,打印2 Knap(1-1,0) returnTrue,打印1 s=0 returnTrue 5-4【八皇后问题】设在初始状态下在国际象棋棋盘上没有任何棋子(皇后)。 然后顺序在第1行,第2行,…。 第8行上布放棋子。 在每一行中有8个可选择位置,但在任一时刻,棋盘的合法布局都必须满足3个限制条件,即任何两个棋子不得放在棋盘上的同一行、或者同一列、或者同一斜线上。 试编写一个递归算法,求解并输出此问题的所有合法布局。 (提示: 用回溯法。 在第n行第j列安放一个棋子时,需要记录在行方向、列方向、正斜线方向、反斜线方向的安放状态,若当前布局合法,可向下一行递归求解,否则可移走这个棋子,恢复安放该棋子前的状态,试探本行的第j+1列。 ) 【解答】此为典型的回溯法问题。 1#次对角线 0#次对角线 0123 2#次对角线 3#次对角线 4#次对角线 5#次对角线 6#次对角线 0#主对角线 1#主对角线 0 1 2 3 3#主对角线 2#主对角线 4#主对角线 6#主对角线 5#主对角线 在解决8皇后时,采用回溯法。 在安放第i行皇后时,需要在列的方向从1到n试探(j=1,…,n): 首先在第j列安放一个皇后,如果在列、主对角线、次对角线方向有其它皇后,则出现攻击,撤消在第j列安放的皇后。 如果没有出现攻击,在第j列安放的皇后不动,递归安放第i+1行皇后。 解题时设置4个数组: col[n]: col[i]标识第i列是否安放了皇后 md[2n-1]: md[k]标识第k条主对角线是否安放了皇后 sd[2n-1]: sd[k]标识第k条次对角线是否安放了皇后 q[n]: q[i]记录第i行皇后在第几列 利用行号i和列号j计算主对角线编号k的方法是k=n+i-j-1;计算次对角线编号k的方法是k=i+j。 n皇后问题解法如下: voidQueen(inti){ for(intj=0;j if(col[j]==0&&md[n+i-j-1]==0&&sd[i+j]==0){//第i行第j列没有攻击 col[j]=md[n+i-j-1]=sd[i+j]=1;q[i]=j;//在第i行第j列安放皇后 if(i==n){//输出一个布局 for(j=0;j cout< } else{Queen(i+1);//在第i+1行安放皇后 col[j]=md[n+i-j-1]=sd[i+j]=0;q[i]=0;//撤消第i行第j列的皇后 } } } 5-5已知f为单链表的表头指针,链表中存储的都是整型数据,试写出实现下列运算的递归算法: (1)求链表中的最大整数。 (2)求链表的结点个数。 (3)求所有整数的平均值。 【解答】 #include classList; classListNode{//链表结点类 friendclassList; private: intdata;//结点数据 ListNode*link;//结点指针 ListNode(constintitem): data(item),link(NULL){}//构造函数 }; classList{//链表类 private: ListNode*first,current; intMax(ListNode*f); intNum(ListNode*f); floatAvg(ListNode*f,int&n); public: List(): first(NULL),current(NULL){}//构造函数 ~List(){}//析构函数 ListNode*NewNode(constintitem);//创建链表结点,其值为item voidNewList(constintretvalue);//建立链表,以输入retvalue结束 voidPrintList();//输出链表所有结点数据 intGetMax(){returnMax(first);}//求链表所有数据的最大值 intGetNum(){returnNum(first);}//求链表中数据个数 floatGetAvg(){returnAvg(first);}//求链表所有数据的平均值 }; ListNode*List: : NewNode(constintitem){//创建新链表结点 ListNode*newnode=newListNode(item); returnnewnode; } voidList: : NewList(constintretvalue){//建立链表,以输入retvalue结束 first=NULL;intvalue;ListNode*q; cout<<"Inputyourdata: \n";//提示 cin>>value;//输入 while(value! =retvalue){//输入有效 q=NewNode(value);//建立包含value的新结点 if(first==NULL)first=current=q;//空表时,新结点成为链表第一个结点 else{current->link=q;current=q;}//非空表时,新结点链入链尾 cin>>value;//再输入 } current->link=NULL;//链尾封闭 } voidList: : PrintList(){//输出链表 cout<<"\nTheListis: \n"; ListNode*p=first; while(p! =NULL){cout< cout<<‘\n’; } (1)求链表中的最大整数 intList: : Max(ListNode*f){//递归算法: 求链表中的最大值 if(f->link==NULL)returnf->data;//递归结束条件 inttemp=Max(f->link);//在当前结点的后继链表中求最大值 if(f->data>temp)returnf->data;//如果当前结点的值还要大,返回当前检点值 elsereturntemp;//否则返回后继链表中的最大值 } (2)求链表的结点个数 intList: : Num(ListNode*f){//递归算法: 求链表中结点个数 if(f==NULL)return0;//空表,返回0 return1+Num(f->link);//否则,返回后继链表结点个数加1 } (3)求所有整数的平均值 floatList: : Avg(ListNode*f,int&n){//递归算法: 求链表中所有元素的平均值 if(f->link==NULL)//链表中只有一个结点,递归结束条件 {n=1;return(float)(f->data);} else{floatSum=Avg(f->link,n)*n;n++;return(f->data+Sum)/n;} } #include"RecurveList.h"//定义在主文件中 intmain(intargc,char*argv[]){ Listtest;intfinished; cout<<“输入建表结束标志数据: ”; cin>>finished;//输入建表结束标志数据 test.NewList(finished);//建立链表 test.PrintList();//打印链表 cout<<"\nTheMaxis: "< cout<<"\nTheNumis: "< cout<<"\nTheAveis: "< printf("HelloWorld! \n"); return0; } 5-6画出下列广义表的图形表示和它们的存储表示: (1)D(A(c),B(e),C(a,L(b,c,d))) (2)J1(J2(J1,a,J3(J1)),J3(J1)) 【解答】 (1)D(A(c),B(e),C(a,L(b,c,d))) (2)J1(J2(J1,a,J3(J1)),J3(J1)) J1 J2 J3 C B A D c b a e L a d c 0J1 2 2 ∧ J1 ∧ A 0B ∧ B 0A 1e 2 ∧ 2 0D D 1c 2 J2 ∧ 1a 2 0J2 2 0C 2 1a C ∧ ∧ 0J3 J3 2 ∧ 0L 1d 1c 1b L 5-7利用广义表的head和tail操作写出函数表达式,把以下各题中的单元素banana从广义表中分离出来: (1)L1(apple,pear,banana,orange) (2)L2((apple,pear),(banana,orange)) (3)L3(((apple),(pear),(banana),(orange))) (4)L4((((apple))),((pear)),(banana),orange) (5)L5((((apple),pear),banana),orange) (6)L6(apple,(pear,(banana),orange)) 【解答】 (1)Head(Tail(Tail(L1))) (2)Head(Head(Tail(L2))) (3)Head(Head(Tail(Tail(Head(L3))))) (4)Head(Head(Tail(Tail(L4)))) (5)Head(Tail(Head(L5))) (6)Head(Head(Tail(Head(Tail(L6))))) 5-8广义表具有可共享性,因此在遍历一个广义表时必需为每一个结点增加一个标志域mark,以记录该结点是否访问过。 一旦某一个共享的子表结点被作了访问标志,以后就不再访问它。 (1)试定义该广义表的类结构; (2)采用递归的算法对一个非递归的广义表进行遍历。 (3)试使用一个栈,实现一
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第五 递归 广义