栈与队列

特殊线性表——栈

栈:限定仅在表尾进行插入和删除操作的线性表

空栈:不含任何数据元素的栈。

允许插入和删除的一端称为栈顶,另一端称为栈底

栈的操作特性:后进先出

栈的顺序存储结构及实现

ADT Stack

Data

   栈中元素具有相同类型及后进先出特性,

   相邻元素具有前驱和后继关系

Operation

   InitStack

      前置条件:栈不存在

      输入:无

      功能:栈的初始化

      输出:无

      后置条件:构造一个空栈

DestroyStack

     前置条件:栈已存在

     输入:无

     功能:销毁栈

     输出:无

     后置条件:释放栈所占用的存储空间

Push

     前置条件:栈已存在

     输入:元素值x

     功能:在栈顶插入一个元素x

     输出:如果插入不成功,抛出异常

     后置条件:如果插入成功,栈顶增加了一个元素

Pop

    前置条件:栈已存在

    输入:无

    功能:删除栈顶元素

    输出:如果删除成功,返回被删元素值,否则,抛出异常

    后置条件:如果删除成功,栈减少了一个元素

GetTop

    前置条件:栈已存在

    输入:无

    功能:读取当前的栈顶元素

    输出:若栈不空,返回当前的栈顶元素值

    后置条件:栈不变

Empty

    前置条件:栈已存在

    输入:无

    功能:判断栈是否为空

    输出:如果栈为空,返回1,否则,返回0

    后置条件:栈不变

endADT

实现代码:

const  int  MAX_SIZE=100;

template  <class T>

class  seqStack

{

    public:

        seqStack ( ) ;

        ~seqStack ( );

        void  Push ( T  x );

        T   Pop ( );

        T   GetTop ( );

        bool  Empty ( );

    private:

        T  data[MAX_SIZE];

        int  top;

}

入栈:

操作接口: void  Push( T  x );

template <class T>

void  seqStack<T>::Push ( T  x)

{

     if (top==MAX_SIZE-1)  throw  “溢出”;

     top++;

     data[top]=x;

 }

判断是否是空栈:

操作接口: bool Empty( )

template <class T>

bool  seqStack<T>::Empty ()

{

     if (top==-1) 

         return true;

     return false;

 }

取栈顶:

操作接口: GetTop(  );

template <class T>

seqStack<T>::GetTop ( )

{

     if (Empty()) throw  ”空栈” ;

     return data[top];

 }

出栈:

操作接口: T Pop(  );

template  <class  T>

seqStack<T>:: Pop ( )

{

     if (top==-1)  throw  “溢出”;

     x=data[top];

      top--;

     return  x;

}

两栈共享空间(双端栈)

两栈共享空间:使用一个数组来存储两个栈,让一个栈的栈底为该数组的始端,另一个栈的栈底为该数组的末端,两个栈从各自的端点向中间延伸。

              

const int Stack_Size=100; 

template <class T>

class BothStack

{

  public:

       BothStack( );

       ~BothStack( );

       void Push(int i, T x);  

       T Pop(int i);         

       T GetTop(int i);      

       bool Empty(int i);    

  private:

       T data[Stack_Size];    

       int top1, top2;       

};

插入:

操作接口:void Push(int i, T x) ;

     1. 如果栈满,则抛出上溢异常;

      2. 判断是插在栈1还是栈2;

       2.1 若在栈1插入,则

             2.1.1 top1加1;

             2.1.2 top1处填入x;

       2.2 若在栈2插入,则

             2.2.1 top2减1;

             2.2.2 top2处填入x;

      template <class T>

     void BothStack<T>::Push(int i, T x )

   {

    if (top1==top2-1)

    throw "上溢";

    if (i==1)

    data[++top1]=x;

    if (i==2)

    data[--top2]=x;

}

删除:

操作接口:T Pop(int i) ;

         1.若是在栈1删除,则

1.1 若栈1为空栈,抛出下溢异常;

1.2 删除并返回栈1的栈顶元素;

        2. 若是在栈2删除,则

       2.1 若栈2为空栈,抛出下溢异常;

       2.2 删除并返回栈2的栈顶元素;

      template <class T>

     T BothStack<T>::Pop(int i){

    if (i==1) {  

        if (top1== -1)   throw "下溢";

        return data[top1--];

      }

     if (i==2) {                          

        if (top2==StackSize)    throw "下溢";

        return data[top2++];

      }

    }

    判断某个栈空:

template <class T>

bool BothStack<T>::Empty(int i)

    if(i==1){

        if(top1==-1)   return 1;

        else   return 0;

    }

    if(i==2)  {

        if(top2==StackSize)  return 1;

        else  return 0;

    }

}

取某个栈栈顶:

template <class T>

T BothStack<T>::GetTop(int i)

{

    if(i==1)  {

        if (top1!=-1)   return data[top1];

    }

    if(i==2)  {

        if(top2!=StackSize)  return data[top2];

   }

}

    栈的链接存储结构:

    将链头作为栈顶,方便操作.

   链栈不需要附设头结点.

    头插法:

template <class T>

class LinkStack

{   

   public:

         LinkStack( ) {top=NULL;};

         ~LinkStack( );           

         void Push(T x);

         T Pop( );

         T GetTop( );

         bool Empty( );

   private:

         Node<T> *top;

}

特殊线性表——队列

队列:只允许在一端进行插入操作,而另一端进行删除操作的线性表。

空队列:不含任何数据元素的队列。

允许插入(也称入队、进队)的一端称为队尾,允许删除(也称出队)的一端称为队头

队列的抽象数据类型定义

ADT  Queue

Data

   队列中元素具有相同类型及先进先出特性,

   相邻元素具有前驱和后继关系

Operation

     InitQueue

        前置条件:队列不存在

        输入:无

        功能:初始化队列

        输出:无

        后置条件:创建一个空队列

   DestroyQueue

     前置条件:队列已存在

     输入:无

     功能:销毁队列

     输出:无

     后置条件:释放队列所占用的存储空间

 EnQueue

     前置条件:队列已存在

     输入:元素值x

     功能:在队尾插入一个元素

     输出:如果插入不成功,抛出异常

     后置条件:如果插入成功,队尾增加了一个元素

DeQueue

     前置条件:队列已存在

     输入:无

     功能:删除队头元素

     输出:如果删除成功,返回被删元素值

     后置条件:如果删除成功,队头减少了一个元素

 GetQueue

     前置条件:队列已存在

     输入:无

     功能:读取队头元素

     输出:若队列不空,返回队头元素

     后置条件:队列不变

Empty

     前置条件:队列已存在

     输入:无

     功能:判断队列是否为空

     输出:如果队列为空,返回1,否则,返回0

     后置条件:队列不变

endADT

  队列的顺序存储结构:

  设置队头、队尾两个指针,队头指针指向队头元素的前一个位置;队尾指针指向队中最后一个元素

  持续入队会出现假溢出现象:

假溢出:当元素被插入到数组中下标最大的位置上之后,队列的空间就用尽了,尽管此时数组的低端还有空闲空间,这种现象叫做假溢出

   

为解决假溢出采用循环队列:将存储队列的数组头尾相接 

           

不存在物理的循环结构,用软件方法实现:

求模rear=rear1% MAXSIZE

  front=(front+1) % MAZSIZE

 

   队空:front==rear

   队满的条件:(rear+1) mod QueueSize==front

实现代码:

const int QueueSize=100;

template <class T>   

class CirQueue{

  public:

      CirQueue( )

      ~ CirQueue( )

      void EnQueue(T x);

     T DeQueue( );            

     T GetQueue( );

     bool Empty( ){

      if (rear==front) return true;

       return false;

   }

  private:

     T data[QueueSize];  

     int front, rear;

};

入队:

template <class T>

 void CirQueue<T>::EnQueue(T x)

 {

   if ((rear+1) % QueueSize ==front) throw "上溢";

   rear=(rear+1) % QueueSize;   

   data[rear]=x;                

 } 

出队:

template <class T>

T CirQueue<T>::DeQueue( )

{

     if (rear==front) throw "下溢";

     front=(front+1) % QueueSize;

     return data[front];

}

读队头元素:

template <class T>

T CirQueue<T>::GetQueue( )

{

    if (rear==front) throw "下溢";

    i=(front+1) % QueueSize

    return data[i];

}

队列长度:

template <class T>

int CirQueue<T>::GetLength( )

{

    if (rear==front) throw "下溢";

    len=(rear-front+ QueueSize) % QueueSize

    return len;

}

队列的链接存储结构:

实现代码:

template <class T>

class LinkQueue

{  

  public:

      LinkQueue( );    

      ~LinkQueue( );

      void EnQueue(T x);

      T DeQueue( );      

      T GetQueue( )

      bool Empty( )

  private:

      Node<T> *front, *rear;

};

构造函数:

template <class T>

LinkQueue<T>::LinkQueue( )

{

     front=new Node<T>;

     front->next=NULL; 

     rear=front;

}

入队:

template <class T>

void LinkQueue<T>::EnQueue(T x)

{

    s=new Node<T>;

    s->data=x;

    s->next=NULL;

    rear->next=s;

    rear=s;

}

出队:

template <class T>

T LinkQueue<T>::DeQueue( )

{

     if (rear==front) throw "下溢";

     p=front->next;

     x=p->data;

     front->next=p->next;       

     delete p;

     if (front->next==NULL) rear=front;  

     return x;

}

循环队列和链队列的比较:

时间性能:

循环队列和链队列的基本操作都需要常数时间O (1)。

空间性能:

循环队列:必须预先确定一个固定的长度,所以有存储元素个数的限制和空间浪费的问题。

链队列:没有队列满的问题,只有当内存没有可用空间时才会出现队列满,但是每个元素都需要一个指针域,从而产生了结构性开销。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值