-----------栈的基本概念

           1. 栈的定义

               栈:只允许在一端进行插入或删除操作的线性表。首先栈是一种线性表,但是限定这种线性表只能在

            一端进行插入和删除操作。如下图:

              

                栈顶:线性表允许进行插入和删除的那一端。

                栈底:固定的,不允许进行插入和删除的另一端。

                空栈:不含任何元素的空表。

                假设某个栈 S = ( a1 , a2 , a3 , a4 , a5 ) ,如上图,则 a1 为栈底元素,a5  为栈顶元素。由于栈

             只能在栈顶进行插入和删除操作,故进栈依次为 a1 , a2 , a3 , a4 , a5 ,而出栈次序为 a5 , a4 , a3 ,

             a2 , a1  。由此可见,栈的一个明显的操作特性可以概括为后进先出(Last In  First Out  , LIFO),

             故又称为后进先出的线性表。

 

               注意:我们每接触一种新的数据结构类型,都应该分别从其逻辑结构存储结构和对数据的运算

           三方面着手,以加深对定义的理解。

           2. 栈的基本操作

              InitStack(&S)    : 初始化一个空栈 S

              StackEmpty(S)  : 判断一个栈是否为空,若栈 S 为空返回 true ,否则返回 false

              Push( &S , x  )  :  进栈,若 栈 S 未满,将 x 加入使之成为新栈顶。

              Pop( &S , &x)  : 出栈,若栈 S 非空,弹出栈顶元素,并用 x 返回。

              GetTop( S , &x )  : 读栈顶元素,若栈 S 非空,用 x 返回栈顶元素。

              ClearStack( &S )  :销毁栈,并释放栈 S 占用的存储空间。

              (注:符号 “ &” 是 C++ 特有的,用来表示引用,有的书上采用  C 语言中的指针类型 “ * ” ,也可以

           达到传址的目的。)

-----------栈的顺序存储结构

           1. 顺序栈的实现

              栈的顺序存储称为顺序栈,它是利用一组地址连续的存储单元存放自栈底到栈顶的数据元素,同时

           附设一个指针(top) 指示当前栈顶的位置。

              ------------------------------------------------------------------------------------------------------------

               栈的顺序存储类型可描述为:

               #define MaxSize 50                                // 定义栈中元素的最大个数

               typedef struct {

                       Elemtype  data[ MaxSize ] ;           //  存放栈中元素

                       int  top ;                                        //  栈顶指针

               } SqStack ;

              ---------------------------------------------------------------------------------------------------------------

               栈顶指针:S.top  , 初始时设置为 S.top = -1 ;

               栈顶元素: S.data[ S.top ]

               进栈操作: 栈不满时,栈顶指针先加 1 ,再送值到栈顶元素

               出栈操作: 栈非空时,先取栈顶元素值, 再将栈顶指针域减 1

               栈空条件: S.top = -1

               栈满条件:  S.top = MaxSize -1

               栈长: S.top + 1 

              由于顺序栈的入栈操作受数组上届的约束,当对栈的最大使用空间估计不足时,有可能发生

          栈上溢出,此时应及时向用户报告消息,以便及时处理,避免出错。

 

              对于栈和后面提到的队列的判空和判满条件会因为实际给的条件不同而变化,以上得到的方法

         以及下面给出的代码实现只是在栈顶指针设定的条件下相应的方法,而其他情况需要具体问题具体

         分析。

              

           2. 顺序栈的基本操作

                栈操作的示意图如上图 “  栈顶指针和栈中元素之间的关系 ” (a) 是空栈,(c) 是A, B,C , D ,E

             共 5 个元素依次入栈后的结果; (d) 是在(c)之后 E , D , C 相继出栈,此时栈中还有 2 个元素,或

            许最近出栈的元素 C , D , E 仍在原先的单元存储着,但 top 指针已经指向了新的栈顶,则 C , D ,E

           已不在栈中了,读者应通过示意图深刻理解栈顶指针的作用。

                下面是顺序栈上常用的基本运算的实现。

                (1)初始化

                --------------------------------------------------------------------------------------------------------------------------------------

                  void  InitStack( &s) {

                        s.top = -1 ;                              // 初始化栈顶指针

                  }

                 -------------------------------------------------------------------------------------------------------------------------------------

                (2)判栈空

                --------------------------------------------------------------------------------------------------------------------------------------

                 bool StackEmpty(s){

                     if( s.top = -1 ){                         // 栈空

                           return true;

                     }

                     else{                                     // 不空

                            return false;

                     }

                 }

               ---------------------------------------------------------------------------------------------------------------------------------------

               (3)进栈

               --------------------------------------------------------------------------------------------------------------------------------------

                 bool Push( SqStack  &s , ElemType x){

                            if ( s.top == MaxSize -1 ){               // 栈满,报错

                                    return false;

                            }

                          s.data[++s.top] = x ;                      // 指针先加1 , 然后再入栈

                          return true ;

                 }

                --------------------------------------------------------------------------------------------------------------------------------------

             (4) 出栈

               --------------------------------------------------------------------------------------------------------------------------------------

              bool Pop( SqStack &s , ElemType &x){

                     if ( s.top == -1 ){                                //  栈满,报错

                          return false;

                     }

                     x = s.data[ s.top - -] ;                        // 先出栈,然后指针再减 1

                     retrun true ;

              }

             -----------------------------------------------------------------------------------------------------------------------------------

             (5)读栈顶元素

             ----------------------------------------------------------------------------------------------------------------------------------

               bool  GetTop( SqStack s , ElemType  &x){       

                     if ( s.top == -1 ){                              // 栈空,报错

                         return  false ;

                     }

                     x = s.data[ s.top ] ;                        // x 记录栈顶元素

                    return true ;

               }

              --------------------------------------------------------------------------------------------------------------------------------

             注意:这里的栈顶指针指向的就是栈顶元素,所以进栈时的操作是 s.data[++s.top] = x ; 

          出栈时的操作是 x = s.data[ s.top - -] ; 

             如果栈顶指针初始化为 s.top = 0 , 即栈顶指针指向栈顶元素的下一个位置,则入栈操作

          变为 s.data[s.top ++] = x ; 出栈操作变为 x = s.data[ - -s.top ] 。

             相应的栈空、栈满条件也会发生变化。

           3. 共享栈

             利用栈底位置相对不变的特性,可以让两个顺序栈共享一个一维数据空间,将两个栈的

           栈底分别设置为共享空间的两端,两个栈顶向共享空间的中间延伸,如下图所示:

            

               两个栈的栈顶指针都指向栈顶元素, top0 = -1 时 0 号栈为空 , top1 = MaxSize 时

            1 号栈为空; 仅当两个栈顶指针相邻(top1 - top0 = 1 ) 时,判断为满。

              当 0 号栈进栈时 top0 先加 1 再赋值 , 1 号栈进栈时 top1 先减 1 再赋值;出栈时刚好

            相反。

              共享栈是为了更有效地利用存储空间,两个栈的空间相互调节,只有在整个存储空间被

            占满时才发生溢出。其存取数据的时间复杂度为 O( 1 )  ,所以对存取效率没有什么影响。

-----------栈的链式存储结构

            采用链式存储的栈称为链栈,链栈的优点是便于多个栈共享存储空间和提高其效率,且不

          存在栈满上溢的情况。通常采用单链表实现,并规定所有操作都是在单链表的表头进行的。

          这里规定链栈没有头结点Lhead 指向栈顶元素,如下图所示:

            

          --------------------------------------------------------------------------------------------------------------------------------

          栈的链式存储类型可描述为:

           typedef  struct  Linknode {

                   ElemType  data ;                                     // 数据域

                   struct  Linknode * next ;                          // 指针域

           } * LiStack ;                                                   // 栈类型定义

         -------------------------------------------------------------------------------------------------------------------------------

         采用链式存储,便于结点的插入和删除。链栈的操作与链表类似。读者需要注意的是,

      对于带头结点和不带头结点的链栈,在具体的实现方面有所不同。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小达人Fighting

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值