第三章 链表2.docx
- 文档编号:7213184
- 上传时间:2023-01-21
- 格式:DOCX
- 页数:26
- 大小:47.54KB
第三章 链表2.docx
《第三章 链表2.docx》由会员分享,可在线阅读,更多相关《第三章 链表2.docx(26页珍藏版)》请在冰豆网上搜索。
第三章链表2
3-1改写顺序栈的进栈成员函数Push(x),要求当栈满时执行一个stackFull()操作进行栈满处理。
其功能是:
动态创建一个比原来的栈数组大二倍的新数组,代替原来的栈数组,原来栈数组中的元素占据新数组的前MaxSize位置。
【解答】template
:
push(constType&item){
if(isFull())stackFull();//栈满,做溢出处理
elements[++top]=item;//进栈
}
template
:
stackFull(){
Type*temp=newType[3*maxSize];//创建体积大二倍的数组
for(inti=0;i<=top;i++)//传送原数组的数据
temp[i]=elements[i];
delete[]elements;//删去原数组
maxSize*=3;//数组最大体积增长二倍
elements=temp;//新数组成为栈的数组空间
}
3-2铁路进行列车调度时,常把站台设计成栈式结构的站台,如右图所示。
试问:
(1)设有编号为1,2,3,4,5,6的六辆列车,顺序开入栈式结构的站台,则可能的出栈序列有多少种?
(2)若进站的六辆列车顺序如上所述,那么是否能够得到435612,325641,154623和135426的出站序列,如果不能,说明为什么不能;如果能,说明如何得到(即写出"进栈"或"出栈"的序列)。
【解答】
(1)可能的不同出栈序列有种。
(2)不能得到435612和154623这样的出栈序列。
因为若在4,3,5,6之后再将1,2出栈,则1,2必须一直在栈中,此时1先进栈,2后进栈,2应压在1上面,不可能1先于2出栈。
154623也是这种情况。
出栈序列325641和135426可以得到。
3
5
6
2
2
4
4
4
4
1
1
1
1
1
1
1
1
33232325325325632564325641
5
3
4
4
1
2
2
2
2
6
1113135********213542135426
3-3试证明:
若借助栈可由输入序列1,2,3,…,n得到一个输出序列p1,p2,p3,…,pn(它是输入序列的某一种排列),则在输出序列中不可能出现以下情况,即存在i (提示: 用反证法) 【解答】 因为借助栈由输入序列1,2,3,…,n,可得到输出序列p1,p2,p3,…,pn,如果存在下标i,j,k,满足i ①i进栈,i出栈,j进栈,j出栈,k进栈,k出栈。 此时具有最小值的排在最前面pi位置,具有中间值的排在其后pj位置,具有最大值的排在pk位置,有pi ②i进栈,i出栈,j进栈,k进栈,k出栈,j出栈。 此时具有最小值的排在最前面pi位置,具有最大值的排在pj位置,具有中间值的排在最后pk位置,有pi ③i进栈,j进栈,j出栈,i出栈,k进栈,k出栈。 此时具有中间值的排在最前面pi位置,具有最小值的排在其后pj位置,有pj ④i进栈,j进栈,j出栈,k进栈,k出栈,i出栈。 此时具有中间值的排在最前面pi位置,具有最大值的排在其后pj位置,具有最小值的排在pk位置,有pk ⑤i进栈,j进栈,k进栈,k出栈,j出栈,i出栈。 此时具有最大值的排在最前面pi位置,具有中间值的排在其后pj位置,具有最小值的排在pk位置,有pk 0m-1 3-4将编号为0和1的两个栈存放于一个数组空间V[m]中,栈底分别处于数组的两端。 当第0号栈的栈顶指针top[0]等于-1时该栈为空,当第1号栈的栈顶指针top[1]等于m时该栈为空。 两个栈均从两端向中间增长。 当向第0号栈插入一个新元素时,使top[0]增1得到新的栈顶位置,当向第1号栈插入一个新元素时,使top[1]减1得到新的栈顶位置。 当top[0]+1==top[1]时或top[0]==top[1]-1时,栈空间满,此时不能再向任一栈加入新的元素。 试定义这种双栈(DoubleStack)结构的类定义,并实现判栈空、判栈满、插入、删除算法。 【解答】 bot[0]top[0]top[1]bot[1] 双栈的类定义如下: #include template private: inttop[2],bot[2];//双栈的栈顶指针和栈底指针 Type*elements;//栈数组 intm;//栈最大可容纳元素个数 public: DblStack(intsz=10);//初始化双栈,总体积m的默认值为10 ~DblStack(){delete[]elements;}//析构函数 voidDblPush(constType&x,inti);//把x插入到栈i的栈顶 intDblPop(inti);//退掉位于栈i栈顶的元素 Type*DblGetTop(inti);//返回栈i栈顶元素的值 intIsEmpty(inti)const{returntop[i]==bot[i];}//判栈i空否,空则返回1,否则返回0 intIsFull()const{returntop[0]+1==top[1];}//判栈满否,满则返回1,否则返回0 voidMakeEmpty(inti);//清空栈i的内容 } template : DblStack(intsz): m(sz),top[0](-1),bot[0](-1),top[1](sz),bot[1](sz){ //建立一个最大尺寸为sz的空栈,若分配不成功则错误处理。 elements=newType[m];//创建栈的数组空间 assert(elements! =NULL);//断言: 动态存储分配成功与否 } template : DblPush(constType&x,inti){ //如果IsFull(),则报错;否则把x插入到栈i的栈顶 assert(! IsFull());//断言: 栈满则出错处理,停止执行 if(i==0)elements[++top[0]]=x;//栈0情形: 栈顶指针先加1,然后按此地址进栈 elseelements[--top[1]]=x;//栈1情形: 栈顶指针先减1,然后按此地址进栈 } template : DblPop(inti){ //如果IsEmpty(i),则不执行退栈,返回0;否则退掉位于栈i栈顶的元素,返回1 if(IsEmpty(i))return0;//判栈空否,若栈空则函数返回0 if(i==0)top[0]--;//栈0情形: 栈顶指针减1 elsetop[1]++;//栈1情形: 栈顶指针加1 return1; } template : DblGetTop(inti){ //若栈不空则函数返回该栈栈顶元素的地址。 if(IsEmpty(inti))returnNULL;//判栈i空否,若栈空则函数返回空指针 return&elements[top[i]];//返回栈顶元素的值 } template if(i==0)top[0]=bot[0]=-1; elsetop[1]=bot[1]=m; } 3-5写出下列中缀表达式的后缀形式: (1)A*B*C (2)-A+B-C+D (3)A*-B+C (4)(A+B)*D+E/(F+A*D)+C (5)A&&B||! (E>F)/*注: 按C++的优先级*/ (6)! (A&&! ((B 【解答】 (1)AB*C* (2)A-B+C-D+ (3)AB-*C+ (4)AB+D*EFAD*+/+C+ (5)AB&&EF>! || (6)ABC &&! CE<|| 3-6根据课文中给出的优先级,回答以下问题: (1)在函数postfix中,如果表达式e含有n个运算符和分界符,问栈中最多可存入多少个元素? (2)如果表达式e含有n个运算符,且括号嵌套的最大深度为6层,问栈中最多可存入多少个元素? 【解答】 (1)在函数postfix中,如果表达式e含有n个运算符和分界符,则可能的运算对象有n+1个。 因此在利用后缀表达式求值时所用到的运算对象栈中最多可存入n+1个元素。 (2)同上。 3-7试利用运算符优先数法,画出对如下中缀算术表达式求值时运算符栈和运算对象栈的变化。 a+b*(c-d)-e↑f/g 【解答】 设在表达式计算时各运算符的优先规则如上一题所示。 因为直接对中缀算术表达式求值时必须使用两个栈,分别对运算符和运算对象进行处理,假设命名运算符栈为OPTR(operator的缩写),运算对象栈为OPND(operand的缩写),下面给出对中缀表达式求值的一般规则: (1)建立并初始化OPTR栈和OPND栈,然后在OPTR栈中压入一个“;” (2)从头扫描中缀表达式,取一字符送入ch。 (3)当ch不等于“;”时,执行以下工作,否则结束算法。 此时在OPND栈的栈顶得到运算结果。 ①如果ch是运算对象,进OPND栈,从中缀表达式取下一字符送入ch; ②如果ch是运算符,比较ch的优先级icp(ch)和OPTR栈顶运算符isp(OPTR)的优先级: 若icp(ch)>isp(OPTR),则ch进OPTR栈,从中缀表达式取下一字符送入ch; 若icp(ch) 若icp(ch)==isp(OPTR)且ch==“)”,则从OPTR栈退出栈顶的“(”,对消括号,然后从中缀表达式取下一字符送入ch; 根据以上规则,给出计算a+b*(c-d)-e↑f/g时两个栈的变化。 步序 扫描项 项类型 动作 OPND栈变化 OPTR栈变化 0 OPTR栈与OPND栈初始化,‘;’进OPTR栈, 取第一个符号 ; 1 a 操作数 a进OPND栈,取下一符号 a ; 2 + 操作符 icp(‘+’)>isp(‘;’),进OPTR栈,取下一符号 a ;+ 3 b 操作数 b进OPND栈,取下一符号 ab ;+ 4 * 操作符 icp(‘*’)>isp(‘+’),进OPTR栈,取下一符号 ab ;+* 5 ( 操作符 icp(‘(’)>isp(‘*’),进OPTR栈,取下一符号 ab ;+*( 6 c 操作数 c进OPND栈,取下一符号 abc ;+*( 7 - 操作符 icp(‘-’)>isp(‘(’),进OPTR栈,取下一符号 ab ;+*(- 8 d 操作数 d进OPND栈,取下一符号 abcd ;+*(- 9 ) 操作符 icp(‘)’) 栈‘c’,退OPTR栈‘-’,计算c–d→s1,结果进 OPND栈 abs1 ;+*( 10 同上 同上 icp(‘)’)==isp(‘(’),退OPTR栈‘(’,对消括号, 取下一符号 abs1 ;+* 11 - 操作符 icp(‘-’) 栈‘b’,退OPTR栈‘*’,计算b*s1→s2,结果进 OPND栈 as2 ;+ 12 同上 同上 icp(‘-’) 栈‘a’,退OPTR栈‘+’,计算a*s2→s3,结果 进OPND栈 s3 ; 13 同上 同上 icp(‘-’)>isp(‘;’),进OPTR栈,取下一符号 s3 ;- 14 e 操作数 e进OPND栈,取下一符号 s3e ;- 15 ↑ 操作符 icp(‘↑’)>isp(‘-’),进OPTR栈,取下一符号 s3e ;-↑ 16 f 操作数 f进OPND栈,取下一符号 s3ef ;-↑ 17 / 操作符 icp(‘/’) 栈‘e’,退OPTR栈‘↑’,计算e↑f→s4,结果 进OPND栈 s3s4 ;- 18 同上 同上 icp(‘/’)>isp(‘-’),进OPTR栈,取下一符号 s3s4 ;-/ 19 g 操作数 g进OPND栈,取下一符号 s3s4g ;-/ 20 ; 操作符 icp(‘;’) 栈‘s4’,退OPTR栈‘/’,计算s4/g→s5,结果 进OPND栈 s3s5 ;- 21 同上 同上 icp(‘;’) 栈‘s3’,退OPTR栈‘-’,计算s3–s5→s6,结 果进OPND栈 s6 ; 22 同上 同上 icp(‘;’)==isp(‘;’),退OPND栈‘s6’,结束 ; 3-8假设以数组Q[m]存放循环队列中的元素,同时以rear和length分别指示环形队列中的队尾位置和队列中所含元素的个数。 试给出该循环队列的队空条件和队满条件,并写出相应的插入(enqueue)和删除(dlqueue)元素的操作。 【解答】 循环队列类定义 #include template public: Queue(int=10); ~Queue(){delete[]elements;} voidEnQueue(Type&item); TypeDeQueue(); TypeGetFront(); voidMakeEmpty(){length=0;}//置空队列 intIsEmpty()const{returnlength==0;}//判队列空否 intIsFull()const{returnlength==maxSize;}//判队列满否 private: intrear,length;//队尾指针和队列长度 Type*elements;//存放队列元素的数组 intmaxSize;//队列最大可容纳元素个数 } 构造函数 template Queue : Queue(intsz): rear(maxSize-1),length(0),maxSize(sz){ //建立一个最大具有maxSize个元素的空队列。 elements=newType[maxSize];//创建队列空间 assert(elements! =0);//断言: 动态存储分配成功与否 } 插入函数 template voidQueue : EnQueue(Type&item){ assert(! IsFull());//判队列是否不满,满则出错处理 length++;//长度加1 rear=(rear+1)%maxSize;//队尾位置进1 elements[rear]=item;//进队列 } 删除函数 template TypeQueue : DeQueue(){ assert(! IsEmpty());//判断队列是否不空,空则出错处理 length--;//队列长度减1 returnelements[(rear-length+maxSize)%maxSize];//返回原队头元素值 } 读取队头元素值函数 template TypeQueue : GetFront(){ assert(! IsEmpty()); returnelements[(rear-length+1+maxSize)%maxSize];//返回队头元素值 } 3-9假设以数组Q[m]存放循环队列中的元素,同时设置一个标志tag,以tag==0和tag==1来区别在队头指针(front)和队尾指针(rear)相等时,队列状态为“空”还是“满”。 试编写与此结构相应的插入(enqueue)和删除(dlqueue)算法。 【解答】 循环队列类定义 #include template public: Queue(int=10); ~Queue(){delete[]Q;} voidEnQueue(Type&item); TypeDeQueue(); TypeGetFront(); voidMakeEmpty(){front=rear=tag=0;}//置空队列 intIsEmpty()const{returnfront==rear&&tag==0;}//判队列空否 intIsFull()const{returnfront==rear&&tag==1;}//判队列满否 private: intrear,front,tag;//队尾指针、队头指针和队满标志 Type*Q;//存放队列元素的数组 intm;//队列最大可容纳元素个数 } 构造函数 template Queue : Queue(intsz): rear(0),front(0),tag(0),m(sz){ //建立一个最大具有m个元素的空队列。 Q=newType[m];//创建队列空间 assert(Q! =0);//断言: 动态存储分配成功与否 } 插入函数 template voidQueue : EnQueue(Type&item){ assert(! IsFull());//判队列是否不满,满则出错处理 rear=(rear+1)%m;//队尾位置进1,队尾指针指示实际队尾位置 Q[rear]=item;
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第三章 链表2 第三 链表