4-2改写顺序栈的进栈成员函数Push(x),要求当栈满时执行一个 stacke硎()操作进行栈满处理。其功能 是:动态创建一个比原来的栈数组大二倍的新数组,代替原来的栈数组,原来栈数组中的元素占据新数组 的前 Maxsize位置。 【解答】 template≤ lass Type> void stack<Iype>;psh( const Type&iem){ if( is Full()stackFull (; ∥栈满,做溢出处理 elements [+top]=item; ∥进栈 template<class Type> void stack<Type>:: stackFul(t Type*lemp= new Type[3* maxie];∥创建体积大二倍的数组 for(inti=0;i<=p;汁+) ∥传送原数组的数据 delete elements 删去原数组 maxSice *=3: ∥数组最大体积增长二倍 elements temp: ∥新数组成为栈的数组空间 4-3铁路进行列车调度时,常把站台设计成栈式结构的站台,如右图所示。试问: (1)设有编号为123.456的六辆列车,顺序开入栈式结构的站台,则可能I 的出栈序列有多少种? 34 (2)若进站的六辆列车顺序如上所述,那么是否能够得到435612,325641 154623和135426的出站序列,如果不能,说明为什么不能;如果能,说明如何 得到即写出"进栈”或"出栈"的序列)。 【解答】 (1)可能的不同出栈序列有(1/(6+1)*CB2=132种。 (2)不能得到435612和154623这样的出栈序列。因为若在4,3,5,6之后再将1,2出栈,则1,2必须 直在栈中,此时1先进栈,2后进栈,2应压在1上面,不可能1先于2出栈。154623也是这种情况。 出栈序列325641和135426可以得到。 3253256 32564325641 135 1354 1354213542135426 4-4试证明:若借助栈可由输入序列1,2,3,…n得到一个输出序列p,P2P3,…,pn(它是输入序列的某 种排列),则在输出序列中不可能出现以下情况,即存在i<j<k,使得p<P<p。(提示:用反证法) 【解答】 因为借助栈由输入序列1,2,3,…,n,可得到输出序列p,P,p,…,p,如果存在下标i,j,k,满足< j<k,那么在输出序列中,可能出现如下5种情况:
(1/(6 1)) 132 6 + C12 = 4-2 改写顺序栈的进栈成员函数 Push (x ),要求当栈满时执行一个 stackFull ( )操作进行栈满处理。其功能 是:动态创建一个比原来的栈数组大二倍的新数组,代替原来的栈数组,原来栈数组中的元素占据新数组 的前 MaxSize 位置。 【解答】template<class Type>void stack<Type> :: push ( const Type & item ) { if ( isFull ( ) ) stackFull ( ); //栈满,做溢出处理 elements [ ++top ] = item; //进栈 } template<class Type> void stack<Type> :: stackFull ( ) { Type * temp = new Type [ 3 * maxSize ]; //创建体积大二倍的数组 for ( int i = 0; i <= top; i++ ) //传送原数组的数据 temp[i] = elements[i]; delete [ ] elements; //删去原数组 maxSize *= 3; //数组最大体积增长二倍 elements = temp; //新数组成为栈的数组空间 } 4-3 铁路进行列车调度时, 常把站台设计成栈式结构的站台,如右图所示。试问: (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 3 32 32 325 325 3256 32564 325641 5 3 4 4 1 2 2 2 2 6 1 1 13 135 1354 13542 13542 135426 4-4 试证明:若借助栈可由输入序列 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出栈。此时具有最小值的排在最前面p位置,具有中间 值的排在其后P位置,具有最大值的排在pk位置,有p<P<p,不可能出现P<Pk<P的情形 ②i进栈,i出栈,j进栈,k进栈,k出栈,j出栈。此时具有最小值的排在最前面p位置,具有最大 值的排在P位置,具有中间值的排在最后pk位置,有p<P<P,不可能出现P<pk<P的情形; ③i进栈,j进栈,j出栈,i出栈,k进栈,k出栈。此时具有中间值的排在最前面p位置,具有最小 值的排在其后P位置,有P<p<Pk不可能出现P<Pk<P的情形; ④i进栈,j进栈,j出栈,k进栈,k出栈,i出栈。此时具有中间值的排在最前面p位置,具有最大 值的排在其后P位置,具有最小值的排在pk位置,有pk<p<P,也不可能出现P<pk<P的情形; ⑤i进栈,j进栈,k进栈,k出栈,j出栈,i出栈。此时具有最大值的排在最前面p位置,具有中间 值的排在其后P位置,具有最小值的排在pk位置,有pk<P<p,也不可能出现p<pk<p的情形 4-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<C)|(C>D))C<E) 【解答】 (AB+C+ (2)A-B+C-D+ (3)AB-*C (4)AB+D*EFAD*+/+C+ (5)AB&&EF>!|1 6ABC<CD>I!&&ICE<Il 4-7设表达式的中缀表示为a*x-b/x↑2,试利用栈将它改为后缀表示ax*bx2↑/-。写出转换过程中栈 的变化。 【解答】 步序扫描项项类型 栈的变化 输出 操作数 直接输出,读下一符号 操作符sp('#')<lp(*'),进栈,读下一符号# 梁作数 直接输出,读下一符号 xspC*')>i2(=),退栈输 σ卹sp("#')<ip(-'),进栈,读下一符号 操作数 直接输出,读下一符号 /操作符p('-')<ip(")进栈,读下一符号#- 7 操作数 直接输出,读下一符号 #-/ 操作符 (/)<igp(↑'),进栈,读下一符号#-/↑ #-/↑ 10#操作符wsp("↑')>ic('#'),退栈输出 ax*bx2↑
① i 进栈,i 出栈,j 进栈,j 出栈,k 进栈,k 出栈。此时具有最小值的排在最前面 pi 位置,具有中间 值的排在其后 pj 位置,具有最大值的排在 pk 位置,有 pi < pj < 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 < pk < pi 的情形; ⑤ i 进栈,j 进栈,k 进栈,k 出栈,j 出栈,i 出栈。此时具有最大值的排在最前面 pi 位置,具有中间 值的排在其后 pj 位置,具有最小值的排在 pk 位置,有 pk < pj < pi, 也不可能出现 pj < pk < pi 的情形; 4-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 < C)||(C > D) ) )||(C < E) 【解答】 (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 > ! || (6) A B C < C D > || ! && ! C E < || 4-7 设表达式的中缀表示为 a * x - b / x↑2,试利用栈将它改为后缀表示 ax * bx2↑/ -。写出转换过程中栈 的变化。 【解答】 步序 扫描项 项类型 动 作 栈的变化 输 出 0 '#' 进栈, 读下一符号 # 1 a 操作数 直接输出, 读下一符号 # a 2 * 操作符 isp ( ' # ' ) < icp ( ' * ' ), 进栈, 读下一符号 # * a 3 x 操作数 直接输出, 读下一符号 # * a x 4 - 操作符 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 ( '↑' ), 进栈, 读下一符号 # -/↑ a x * b x 9 2 操作数 直接输出, 读下一符号 # -/↑ a x * b x 2 10 # 操作符 isp ( '↑' ) > icp ( ' # ' ), 退栈输出 # -/ a x * b x 2↑ isp ( ' / ' ) > icp ( ' # ' ), 退栈输出 # - a x * b x 2↑/ isp ( ' - ' ) > icp ( ' # ' ), 退栈输出 # a x * b x 2↑/ -
结束 4-9假设以数组Q[m]存放循环队列中的元素,同时以ream和 length分别指示环形队列中的队尾位置和队列 中所含元素的个数。试给出该循环队列的队空条件和队满条件,并写出相应的插入( enqueue)和删除( dequeue) 元素的操作 【解答】 循环队列类定义 #include <assert h> template <class Type> class Queue i ∥循环队列的类定义 Queue( int10 ) void EnQueue(Type item ) Type Dequeue(片 Type GetFront ( 置空队列 int lsEmpry ()const i return length==0;1 ∥判队列空否 int Is Full( const i return length = maxSize; 1 ∥判队列满否 prvate int rear, length: /队尾指针和队列长度 ∥存放队列元素的数组 int maxsize; /队列最大可容纳元素个数 构造函数 template <class Type Queue<Type>: Queue( int s=): rear(maxsie-1), length(0), maxIe(s=)i ∥建立一个最大具有 maxie个元素的空队列 ents new Type ∥创建队列空间 assert( elements =0); 断言:动态存储分配成功与否 插入函数 template<class Type> void Queue<Type>: EnQueue( Type &item )i assert(! IsFull(): ∥判队列是否不满,满则出错处理 length++ ∥长度加1 rear+1)%max Size; /队尾位置进 elementsrear]= item ∥进队列 删除函数 template<class Type> Type Queue<Type>: DeQueue()i assert(! IsEmpty()); ∥判断队列是否不空,空则出错处理 length; 队列长度减1 return elements[(rear-leng th+max Sie)% maxsice] 返回原队头元素值
结束 4-9 假设以数组 Q[m]存放循环队列中的元素, 同时以 rear 和 length 分别指示环形队列中的队尾位置和队列 中所含元素的个数。试给出该循环队列的队空条件和队满条件, 并写出相应的插入(enqueue)和删除(dlqueue) 元素的操作。 【解答】 循环队列类定义 #include <assert.h> template <class Type> class Queue { //循环队列的类定义 public: Queue ( int=10 ); ~Queue ( ) { delete [ ] elements; } void EnQueue ( Type & item ); Type DeQueue ( ); 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 <class Type> Queue<Type>:: Queue ( int sz ) : rear (maxSize-1), length (0), maxSize (sz) { //建立一个最大具有 maxSize 个元素的空队列。 elements = new Type[maxSize]; //创建队列空间 assert ( elements != 0 ); //断言: 动态存储分配成功与否 } 插入函数 template<class Type> void Queue<Type> :: EnQueue ( Type &item ) { assert ( ! IsFull ( ) ); //判队列是否不满,满则出错处理 length++; //长度加 1 rear = ( rear +1) % maxSize; //队尾位置进 1 elements[rear] = item; //进队列 } 删除函数 template<class Type> Type Queue<Type> :: DeQueue ( ) { assert ( ! IsEmpty ( ) ); //判断队列是否不空,空则出错处理 length--; //队列长度减 1 return elements[(rear-length+maxSize) % maxSize]; //返回原队头元素值
读取队头元素值函数 template<class Type> Type Queue<Type>: GetFront(i assert(! IsEmpry() return elements[(rear-leng th+ 1+max Sie)% maxIe]; ∥返回队头元素值 4-10假设以数组Qm存放循环队列中的元素,同时设置一个标志tag,以lag==0和lag==1来区别在队 头指针(on)和队尾指针(rear)相等时,队列状态为“空”还是“满”。试编写与此结构相应的插入( enqueue)和 删除( dequeue)算法。 【解答】 循环队列类定义 #include <assert h> template <class Type> class Queue i ∥循环队列的类定义 Queue( int10 ) -Oueue delete [0; void EnQueue(Type item ) Type DeQueue ( Type GetFront ( void Make Empty (tfront=rear =tag=0;) 置空队列 int Is Empry() const{ return front==rear&&lag==0;}∥判队列空否 int sFull() const{ return front==rea&&lag==1;}∥判队列满否 int rear, front, tag: 队尾指针、队头指针和队满标志 Type Q ∥放队列元素的数组 队列最大可容纳元素个数 构造函数 Queue<Type: Queue( int s=): rear(O), front(O), tag(O), m(s=)t ∥建立一个最大具有m个元素的空队列 ∥创建队列空间 assert(Q=0); 断言:动态存储分配成功与否 插入函数 ){ sert(! IsFull(): ∥判队列是否不满,满则出错处理 rear=( rear+1)% m 队尾位置进1,队尾指针指示实际队尾位置 ∥进队列 ∥标志改1,表示队列不空
} 读取队头元素值函数 template<class Type> Type Queue<Type> :: GetFront ( ) { assert ( ! IsEmpty ( ) ); return elements[(rear-length+1+maxSize) % maxSize]; //返回队头元素值 } 4-10 假设以数组 Q[m]存放循环队列中的元素, 同时设置一个标志 tag,以 tag == 0 和 tag == 1 来区别在队 头指针(front)和队尾指针(rear)相等时,队列状态为“空”还是“满”。试编写与此结构相应的插入(enqueue)和 删除(dlqueue)算法。 【解答】 循环队列类定义 #include <assert.h> template <class Type> class Queue { //循环队列的类定义 public: Queue ( int=10 ); ~Queue ( ) { delete [ ] Q; } void EnQueue ( Type & item ); Type DeQueue ( ); Type GetFront ( ); void MakeEmpty ( ) { front = rear = tag = 0; } //置空队列 int IsEmpty ( ) const { return front == rear && tag == 0; } //判队列空否 int IsFull ( ) const { return front == rear && tag == 1; } //判队列满否 private: int rear, front, tag; //队尾指针、队头指针和队满标志 Type *Q; //存放队列元素的数组 int m; //队列最大可容纳元素个数 } 构造函数 template <class Type> Queue<Type>:: Queue ( int sz ) : rear (0), front (0), tag(0), m (sz) { //建立一个最大具有 m 个元素的空队列。 Q = new Type[m]; //创建队列空间 assert ( Q != 0 ); //断言: 动态存储分配成功与否 } 插入函数 template<class Type> void Queue<Type> :: EnQueue ( Type &item ) { assert ( ! IsFull ( ) ); //判队列是否不满,满则出错处理 rear = ( rear + 1 ) % m; //队尾位置进 1, 队尾指针指示实际队尾位置 Q[rear] = item; //进队列 tag = 1; //标志改 1,表示队列不空 }
删除函数 emplate<class Type> Type Queue<type>: DeQueue (i ( IsEmpry () ∥判断队列是否不空,空则出错处理 front=(front +1)% /队头位置进1,队头指针指示实际队头的前一位置 ∥标志改0,表示栈不满 return @fron; ∥返回原队头元素的值 读取队头元素函数 template<class Type> Type Queue<Type>: GetFront (i assert(! IsEmpty()); ∥判断队列是否不空,空则出错处理 return o[front+ 1)% m]: ∥返回队头元素的值 4-11若使用循环链表来表示队列,p是链表中的一个指针。试基于此结构给出队列的插λ( enqueue)和删除 ( dequeue)算法,并给出p为何值时队列空。 【解答】 链式队列的类定义 template <class Type> class queue ∥链式队列类的前视定义 late <class Type> class QueueNode i ∥链式队列结点类定义 class Queue<Type> Type data; ∥数据域 QueueNode<Type ∥链域 OueueNode( Type d=0, OueteNode=NULL):da(d,hmk(D{}m构造函数 template <class Type> class Queue i ∥链式队列类定义 publie Queue(:P(NULL )0 ∥构造函数 -Queue (i ∥析构函数 void EnQueue const Type item ) 将iem加入到队列中 Type DeQueue ( 删除并返回队头元素 Type GetFront ( M查看队头元素的值 void Make Empty o: ∥置空队列,实现与~ Queue()相同 int IsEmpty()const( return P== NULL; j ∥判队列空否 vate: QueueNode<Type> *p; /队尾指针(在循环链表中) 队列的析构函数 template <class Type> Queue<Type>: -Queue (i 队列的析构函数
删除函数 template<class Type> Type Queue<Type> :: DeQueue ( ) { assert ( ! IsEmpty ( ) ); //判断队列是否不空,空则出错处理 front = ( front + 1 ) % m; //队头位置进 1, 队头指针指示实际队头的前一位置 tag = 0; //标志改 0, 表示栈不满 return Q[front]; //返回原队头元素的值 } 读取队头元素函数 template<class Type> Type Queue<Type> :: GetFront ( ) { assert ( ! IsEmpty ( ) ); //判断队列是否不空,空则出错处理 return Q[(front + 1) % m]; //返回队头元素的值 } 4-11 若使用循环链表来表示队列,p 是链表中的一个指针。试基于此结构给出队列的插入(enqueue)和删除 (dequeue)算法,并给出 p 为何值时队列空。 【解答】 链式队列的类定义 template <class Type> class Queue; //链式队列类的前视定义 template <class Type> class QueueNode { //链式队列结点类定义 friend class Queue<Type>; private: Type data; //数据域 QueueNode<Type> *link; //链域 public: QueueNode ( Type d = 0, QueueNode *l = NULL ) : data (d), link (l) { } //构造函数 }; template <class Type> class Queue { //链式队列类定义 public: Queue ( ) : p ( NULL ) { } //构造函数 ~Queue ( ); //析构函数 void EnQueue ( const Type & item ); //将 item 加入到队列中 Type DeQueue ( ); //删除并返回队头元素 Type GetFront ( ); //查看队头元素的值 void MakeEmpty ( ); //置空队列,实现与~Queue ( ) 相同 int IsEmpty ( ) const { return p == NULL; } //判队列空否 private: QueueNode<Type> *p; //队尾指针(在循环链表中) }; 队列的析构函数 template <class Type> Queue<Type>::~Queue ( ) { //队列的析构函数