1、第4章习题4-1 改写顺序栈的进栈成员函数Push (x ),要求当栈满时执行一个stackFull ( )操作进行栈满处理。其功能是:动态创建一个比原来的栈数组大二倍的新数组,代替原来的栈数组,原来栈数组中的元素占据新数组的前MaxSize位置。【解答】templatevoid stack : push ( const Type & item ) if ( isFull ( ) ) stackFull ( ); /栈满,做溢出处理 elements +top = item; /进栈 template void stack : stackFull ( ) Type * temp = new T
2、ype 3 * maxSize ; /创建体积大二倍的数组 for ( int i = 0; i = top; i+ ) /传送原数组的数据tempi = elementsi; delete elements; /删去原数组 maxSize *= 3; /数组最大体积增长二倍 elements = temp; /新数组成为栈的数组空间 4-2 铁路进行列车调度时, 常把站台设计成栈式结构的站台,如右图所示。试问: (1) 设有编号为1,2,3,4,5,6的六辆列车, 顺序开入栈式结构的站台, 则可能的出栈序列有多少种? (2) 若进站的六辆列车顺序如上所述, 那么是否能够得到435612, 3
3、25641, 154623和135426的出站序列, 如果不能, 说明为什么不能; 如果能, 说明如何得到(即写出进栈或出栈的序列)。【解答】 (1) 可能的不同出栈序列有 种。 (2) 不能得到435612和154623这样的出栈序列。因为若在4, 3, 5, 6之后再将1, 2出栈,则1, 2必须一直在栈中,此时1先进栈,2后进栈,2应压在1上面,不可能1先于2出栈。154623也是这种情况。出栈序列325641和135426可以得到。3562244 4411111111 3 32 32 325 325 3256 32564 3256415344122226 1 1 13 135 * *2
4、 13542 1354264-3 试证明:若借助栈可由输入序列1, 2, 3, , n得到一个输出序列p1, p2, p3, , pn (它是输入序列的某一种排列),则在输出序列中不可能出现以下情况,即存在i j k,使得pj pk pi。(提示:用反证法)【解答】 因为借助栈由输入序列1, 2, 3, , n,可得到输出序列p1, p2, p3, , pn ,如果存在下标i, j, k,满足i j k,那么在输出序列中,可能出现如下5种情况: i进栈,i出栈,j进栈,j出栈,k进栈,k出栈。此时具有最小值的排在最前面pi位置,具有中间值的排在其后pj位置,具有最大值的排在pk位置,有pi p
5、j pk, 不可能出现pj pk pi的情形; i进栈,i出栈,j进栈,k进栈,k出栈,j出栈。此时具有最小值的排在最前面pi位置,具有最大值的排在pj位置,具有中间值的排在最后pk位置,有pi pk pj , 不可能出现pj pk pi的情形; i进栈,j进栈,j出栈,i出栈,k进栈,k出栈。此时具有中间值的排在最前面pi位置,具有最小值的排在其后pj位置,有pj pi pk, 不可能出现pj pk pi的情形; i进栈,j进栈,j出栈,k进栈,k出栈,i出栈。此时具有中间值的排在最前面pi 位置,具有最大值的排在其后pj位置,具有最小值的排在pk位置,有pk pi pj, 也不可能出现pj
6、 pk pi的情形; i进栈,j进栈,k进栈,k出栈,j出栈,i出栈。此时具有最大值的排在最前面pi 位置,具有中间值的排在其后pj位置,具有最小值的排在pk位置,有pk pj pi, 也不可能出现pj pk pi的情形;0 m-14-4 将编号为0和1的两个栈存放于一个数组空间Vm中,栈底分别处于数组的两端。当第0号栈的栈顶指针top0等于-1时该栈为空,当第1号栈的栈顶指针top1等于m时该栈为空。两个栈均从两端向中间增长。当向第0号栈插入一个新元素时,使top0增1得到新的栈顶位置,当向第1号栈插入一个新元素时,使top1减1得到新的栈顶位置。当top0+1 = top1时或top0 =
7、 top1-1时,栈空间满,此时不能再向任一栈加入新的元素。试定义这种双栈(Double Stack)结构的类定义,并实现判栈空、判栈满、插入、删除算法。【解答】bot0 top0 top1 bot1 双栈的类定义如下: #include template class DblStack /双栈的类定义 private: int top2, bot2; /双栈的栈顶指针和栈底指针 Type *elements; /栈数组 int m; /栈最大可容纳元素个数 public: DblStack ( int sz =10 ); /初始化双栈, 总体积m的默认值为10 DblStack ( ) del
8、ete elements; /析构函数 void DblPush ( const Type& x, int i ); /把x插入到栈i的栈顶 int DblPop ( int i ); /退掉位于栈i栈顶的元素 Type * DblGetTop ( int i ); /返回栈i栈顶元素的值 int IsEmpty ( int i ) const return topi = boti; /判栈i空否, 空则返回1, 否则返回0 int IsFull ( ) const return top0+1 = top1; /判栈满否, 满则返回1, 否则返回0 void MakeEmpty ( int i
9、 ); /清空栈i的内容 template DblStack : DblStack ( int sz ) : m(sz), top0 (-1), bot0(-1), top1(sz), bot1(sz) /建立一个最大尺寸为sz的空栈, 若分配不成功则错误处理。 elements = new Typem; /创建栈的数组空间 assert ( elements != NULL ); /断言: 动态存储分配成功与否 template void DblStack : DblPush ( const Type& x, int i ) /如果IsFull ( ),则报错;否则把x插入到栈i的栈顶 as
10、sert ( !IsFull ( ) ); /断言: 栈满则出错处理,停止执行 if ( i = 0 ) elements +top0 = x; /栈0情形:栈顶指针先加1, 然后按此地址进栈 else elements-top1 = x; /栈1情形:栈顶指针先减1, 然后按此地址进栈 template int DblStack : DblPop ( int i ) /如果IsEmpty ( i ),则不执行退栈,返回0;否则退掉位于栈i栈顶的元素,返回1 if ( IsEmpty ( i ) ) return 0; /判栈空否, 若栈空则函数返回0 if ( i = 0 ) top0-;
11、/栈0情形:栈顶指针减1 else top1+; /栈1情形:栈顶指针加1 return 1; template Type * DblStack : DblGetTop ( int i ) /若栈不空则函数返回该栈栈顶元素的地址。 if ( IsEmpty ( int i ) ) return NULL; /判栈i空否, 若栈空则函数返回空指针 return& elements topi ; /返回栈顶元素的值 template void MakeEmpty ( int i ) if ( i = 0 ) top0 = bot0 = -1; else top1 = bot1 = m; 4-5 写
12、出下列中缀表达式的后缀形式: (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 D) ) )|(C ! | (6) A B C | ! & ! C E | 4-6 根据课文中给出的优先级,回答以下问题: (1) 在函数postfix中,如果表达式e含有n个运算符和分界符,问栈中最多可存入多少个元素? (2) 如果表达式e含有n个运算符,且括号嵌套的最大深度为6层,问栈中最多可
13、存入多少个元素?【解答】(1) 在函数postfix中,如果表达式e含有n个运算符和分界符,则可能的运算对象有n+1个。因此在利用后缀表达式求值时所用到的运算对象栈中最多可存入n+1个元素。(2) 同上。4-7 设表达式的中缀表示为a * x - b / x2,试利用栈将它改为后缀表示ax * bx2/ -。写出转换过程中栈的变化。【解答】若设当前扫描到的运算符ch的优先级为icp(ch),该运算符进栈后的优先级为isp(ch),则可规定各个算术运算符的优先级如下表所示。 运算符 ; ( *,/, % +, - ) isp 0 1 7 5 3 8 icp 0 8 6 4 2 1 isp也叫做栈
14、内(in stack priority)优先数,icp也叫做栈外(in coming priority)优先数。当刚扫描到的运算符ch的icp(ch)大于isp(stack)时,则ch进栈;当刚扫描到的运算符ch的icp(ch)小于isp(stack)时,则位于栈顶的运算符退栈并输出。从表中可知,icp(“(”)最高,但当“(”进栈后,isp(“(”)变得极低。其它运算符进入栈中后优先数都升1,这样可体现在中缀表达式中相同优先级的运算符自左向右计算的要求。运算符优先数相等的情况只出现在括号配对“)”或栈底的“;”号与输入流最后的“;”号配对时。前者将连续退出位于栈顶的运算符,直到遇到“(”为止
15、。然后将“(”退栈以对消括号,后者将结束算法。步序扫描项项类型 动 作栈的变化 输 出 0 ; 进栈, 读下一符号; 1 a操作数 直接输出, 读下一符号;A 2 *操作符 isp ( ; ) icp ( - ), 退栈输出; a x * isp ( ; ) icp ( - ), 进栈, 读下一符号; -a x * 5 b操作数 直接输出, 读下一符号; -a x * b 6 /操作符 isp ( - ) icp ( / ), 进栈, 读下一符号 ; -/a x * b 7 x操作数 直接输出, 读下一符号; -/a x * b x 8 操作符 isp ( / ) icp ( ; ), 退栈输
16、出; -/a x * b x 2 isp ( / ) icp ( ; ), 退栈输出; -a x * b x 2/ isp ( - ) icp ( ; ), 退栈输出; a x * b x 2/ - 结束4-8 试利用运算符优先数法,画出对如下中缀算术表达式求值时运算符栈和运算对象栈的变化。 a + b * (c - d) - ef / g 【解答】 设在表达式计算时各运算符的优先规则如上一题所示。因为直接对中缀算术表达式求值时必须使用两个栈,分别对运算符和运算对象进行处理,假设命名运算符栈为OPTR (operator的缩写),运算对象栈为OPND(operand的缩写),下面给出对中缀表达
17、式求值的一般规则:(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) isp ( ; ), 进OPTR栈, 取下一符号a; +3b操作数 b 进OPND栈,
18、取下一符号a b; +4*操作符 icp ( * ) isp ( + ), 进OPTR栈, 取下一符号a b; + *5(操作符 icp ( ( ) isp ( * ), 进OPTR栈, 取下一符号a b; + * (6c操作数 c 进OPND栈, 取下一符号a b c; + * (7-操作符 icp ( - ) isp ( ( ), 进OPTR栈, 取下一符号a b; + * ( -8d操作数 d 进OPND栈, 取下一符号a b c d; + * ( -9)操作符 icp ( ) ) isp ( - ), 退OPND栈 d, 退OPND 栈 c, 退OPTR栈 -, 计算 c d s1,
19、结果进 OPND栈a b s1; + * (10同上同上 icp ( ) ) = isp ( ( ), 退OPTR栈(, 对消括号, 取下一符号a b s1; + * 11-操作符 icp ( - ) isp ( * ), 退OPND栈 s1, 退OPND 栈 b, 退OPTR栈 *, 计算 b * s1 s2, 结果进 OPND栈a s2; + 12同上同上 icp ( - ) isp ( ; ), 进OPTR栈, 取下一符号s3 ; -14e操作数 e 进OPND栈, 取下一符号s3 e; -15操作符 icp ( ) isp ( - ), 进OPTR栈, 取下一符号s3 e; -16f操
20、作数 f 进OPND栈, 取下一符号s3 e f; -17/操作符 icp ( / ) isp ( - ), 进OPTR栈, 取下一符号s3 s4; - /19g操作数 g 进OPND栈, 取下一符号s3 s4 g; - /20;操作符 icp ( ; ) isp ( / ), 退OPND栈 g, 退OPND 栈 s4, 退OPTR栈 /, 计算 s4 / g s5, 结果 进OPND栈s3 s5; -21同上同上 icp ( ; ) isp ( - ), 退OPND栈 s5, 退OPND 栈 s3, 退OPTR栈 - , 计算 s3 s5 s6, 结 果进OPND栈s6;22同上同上 icp
21、 ( ; ) = isp ( ; ), 退OPND栈 s6, 结束;4-9 假设以数组Qm存放循环队列中的元素, 同时以rear和length分别指示环形队列中的队尾位置和队列中所含元素的个数。试给出该循环队列的队空条件和队满条件, 并写出相应的插入(enqueue)和删除(dlqueue)元素的操作。【解答】循环队列类定义 #include template class Queue /循环队列的类定义 public: Queue ( int=10 ); Queue ( ) delete elements; void EnQueue ( Type & item ); Type DeQueue
22、( ); Type GetFront ( ); void MakeEmpty ( ) length = 0; /置空队列 int IsEmpty ( ) const return length = 0; /判队列空否 int IsFull ( ) const return length = maxSize; /判队列满否 private: int rear, length; /队尾指针和队列长度 Type *elements; /存放队列元素的数组 int maxSize; /队列最大可容纳元素个数 构造函数 template Queue: Queue ( int sz ) : rear (m
23、axSize-1), length (0), maxSize (sz) /建立一个最大具有maxSize个元素的空队列。 elements = new TypemaxSize; /创建队列空间 assert ( elements != 0 ); /断言: 动态存储分配成功与否 插入函数 template void Queue : EnQueue ( Type &item ) assert ( ! IsFull ( ) ); /判队列是否不满,满则出错处理 length+; /长度加1rear = ( rear +1) % maxSize; /队尾位置进1 elementsrear = item; /进队列 删除函数 template Type Queue : DeQueue ( ) assert ( ! Is
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1