第5章递归与广义表Word格式文档下载.docx
- 文档编号:16368968
- 上传时间:2022-11-23
- 格式:DOCX
- 页数:20
- 大小:67.22KB
第5章递归与广义表Word格式文档下载.docx
《第5章递归与广义表Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《第5章递归与广义表Word格式文档下载.docx(20页珍藏版)》请在冰豆网上搜索。
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;
No.oftheElements:
while(size<
1)cin>
size;
RecurveArrayra(size);
ra.InputArray();
cout<
\nThemaxis:
<
ra.MaxKey(ra.MaxSize)<
endl;
\nThesumis:
ra.Sum(ra.MaxSize)<
\ntheavris:
ra.Average(ra.MaxSize)<
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));
0,n>
0
}
(2)为了将递归算法改成非递归算法,首先改写原来的递归算法,将递归语句从
结构中独立出来:
unsignedv;
if(m==0)returnn+1;
if(n==0)returnakm(m-1,1);
//m>
0,n==0
v=akm(m,n-1));
//m>
returnakm(m-1,v);
计算akm(2,1)的递归调用树如图所示:
akm(2,1)
akm=5
v=3
akm(1,3)
v=akm(2,0)
v=4
akm=3
akm(0,4)=5
v=akm(1,2)
akm(1,1)
akm(0,3)=4
v=akm(1,1)
akm(0,2)=3
v=akm(1,0)
v=2
akm(0,1)=2
v=akm(1,0)
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
111102
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“stack.h”
#definemaxSize3500;
unsignedakm(unsignedm,unsignedn){
structnode{unsignedvm,vn;
}
stack<
node>
st(maxSize);
nodew;
unsignedv;
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;
}//直到akm(0,akm(1,*))
w=st.GetTop();
v=w.vn++;
//计算v=akm(1,*)+1
if(st.IsEmpty()==0)//如果栈不空,改栈顶为(m-1,v)
{w=st.GetTop();
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<
W[n]<
‘,’;
returnTrue;
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
Knap(3-4,4)
Knap(3,2)
s=-1<
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#主对角线
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<
n;
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<
q[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)求所有整数的平均值。
//定义在头文件"
RecurveList.h"
中
classList;
classListNode{//链表结点类
friendclassList;
private:
intdata;
//结点数据
ListNode*link;
//结点指针
ListNode(constintitem):
data(item),link(NULL){}//构造函数
classList{//链表类
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>
//再输入
current->
link=NULL;
//链尾封闭
PrintList(){//输出链表
\nTheListis:
ListNode*p=first;
while(p!
=NULL){cout<
p->
data<
'
p=p->
link;
cout<
‘\n’;
(1)求链表中的最大整数
intList:
Max(ListNode*f){//递归算法:
求链表中的最大值
if(f->
link==NULL)returnf->
data;
//递归结束条件
inttemp=Max(f->
link);
//在当前结点的后继链表中求最大值
data>
temp)returnf->
//如果当前结点的值还要大,返回当前检点值
elsereturntemp;
//否则返回后继链表中的最大值
(2)求链表的结点个数
Num(ListNode*f){//递归算法:
求链表中结点个数
if(f==NULL)return0;
//空表,返回0
return1+Num(f->
//否则,返回后继链表结点个数加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"
//定义在主文件中
intmain(intargc,char*argv[]){
Listtest;
intfinished;
“输入建表结束标志数据:
”;
cin>
finished;
//输入建表结束标志数据
test.NewList(finished);
//建立链表
test.PrintList();
//打印链表
\nTheMaxis:
test.GetMax();
\nTheNumis:
test.GetNum();
\nTheAveis:
test.GetAve()<
\n'
printf("
HelloWorld!
);
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
d
0J1
∧
0B
0A
1e
2
0D
1c
1a
0J2
0C
1a
0J3
0L
1d
1b
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文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 递归 广义