3.4队列

3.4.1抽象数据类型队列的定义

      和栈相反,队列是一种先进先出(FIFO)线性表。它只允许在表的一端进行插入,在另一端进行删除元素。这和我们的排队是类似的,先来排在前面,办完事先走。在队列中允许插入的一端称为队尾(rear),允许删除的一端称为对头(front)。

      队列的操作和栈类似,也有8个,不同的是队列是一个在表尾一个在表头,栈在栈顶。

3.4.2链队列——队列的链式表示和实现

        和线性表类似,队列也可以由两种存储表示。
        用链表表示的队列称为链队列。一个链队列显然需要两个分别指示队头和队尾的指针(分别称为头指针和尾指针)才能唯一确定。为了操作方便,我们也给链队列添加一个头结点(可以保证第一个结点也像其它结点一样有前驱),并令头指针指向头结点。空链队列的头和尾指针都指向头结点。



//------------------单链队列——队列的链式存储结构------------------------------------------------------------------------
   typedef struct   QNode{
              QElemType     data;
              struct   QNode *next;
   }QNode,*QueuePtr;

  typedef struct{
              QueuePtr    front;             
              QueuePtr    rear;                //和循环队列的顺序存储结构对比,循环队列的顺序存储结构,是用int 来描述front;链式是用自定义的指针*QueuePtr
  }LinkQueue;

//------------------基本操作的函数原型说明------------------------------------
          类似线性表链式存储结构的操作,所以省略。参考前面链式线性表。

//-----------------基本操作的算法描述(部分)-------------------------------
Status InitQueue(LinkQueue &Q)
{
    //构造一个空队列Q
    Q.front = Q.rear = (QueuePtr)malloc(sizeof(QNode));          //和后面循环队列,构造一个空队列相比下
    if(!Q.front)exit(OVERFLOW);
    Q.front->next = NULL;
    return OK;
}

Status DestoryQueue(LinkQueue &Q)
{
    //销毁队列Q  
    while(Q.front)
    {
         Q.rear = Q.front->next;
         free(Q.front);
         Q.front = Q.rear;
    }
    return OK;
}

Status EnQueue(LinkQueue &Q,QElemType e)
{
     //插入新的元素e到队列Q
     p = (QueuePtr)malloc(sizeof(QNode));                 //分配一个结点?队列结点QNode?
     if(!p)exit(OVERFLOW);
     p->data = e; p->next = NULL;
     Q.rear->next = p;
     Q.rear = p;
     return OK;
}

Status DeQueue(LinkQueue &Q,QElemType &e)
{
     //删除非空队列Q的头元素,并用e返回
     if(Q.front = Q.rear) return ERROR;
     p = Q.front->next; e = p->data;
     Q.front->next = p->next;
     if(Q.rear ==p) Q.rear == Q.front;                            //如果p即是对头元素也是队尾元素,那么置队列为空;因为如果只有p那么p->next是不存在为NULL。
     free(p);
     return OK;
}

       在上述模块的算法描述中,注意删除队列头元素算法中的特殊情况。一般情况下,删除队列头元素,只需要修改头指针就OK了,但是队列只有一个元素时候,删除后尾指针也就丢了,因此需要对队尾指针重新赋值(指向头结点)。
3.4.3循环队列——队列的顺序表示和实现
        和顺序栈类似,在队列的顺序存储结构中,除了一组地址连续的存储单元存储队列元素外,还需要外设两个指针front和rear分别指示队列的头元素和尾元素的位置。为了在C语言中描述方便,在此我们约定:初始化建空队列时,令front=rear=0,每当插入新的队列尾元素时,”尾指针加1“;每当删除头指针元素时,”头指针增1“。
        假设为一个队列分配的最大空间为6,则当处于下图(图d)的状态时,不能再插入元素,因为会越界而导致程序代码被破坏。然而,又不如顺序栈那样新增分配空间,因为队列的实际可用空间并未占满。一个巧妙的办法是将顺序队列臆造为一个环状的空间,如下图所示,称之为循环队列。

                              

        如下图(3.14a)所示循环队列中,队列头元素是J3,队列尾元素是J5,之后J6、J7和J8相继插入,则队列空间被占满。如图(b)所示,此时Q.front = Q.rear,反之,若J3、J4和J5相继从图(a)队列中删除,此时队列为空,如图(c)所示。此时,Q.front = Q.rear,由此可见,只凭等式 Q.front = Q.rear无法判断队列是空还是满。
        有两种方法处理:其一是另设一个标志位以区别队列是空还是满;其二是少用一个元素空间,约定为当队列头指针在队列尾指针的下一个位置(指环状的下一位置)上作为队列成满状态标志。
         在上述分析中可见,C语言中不能用动态分配的一维数组来实现循环队列。若用户应用程序中设有循环队列,那么必须为它设定一个最大长度,如果无法估测队列的最大长度,宜采用链队列:
         循环队列类型的模块说明如下:
     //------------------循环队列-----------队列的顺序存储结构-----------
    #define  MAXQSIZE  100      //最大队列长度
    typedef  struct{
           QElemType  *base;          //初始化动态分配的存储空间,相当于指定分配的数组的基地址;
           int front;                               //因为是队列的顺序存储结构,所以头结点用int型来描述,上面的链式存储结构就是用的自定义的指针*QueuePtr来描述。
           int rear;
    }SqQueue;

   //-----------------循环队列的基本操作的算法描述--------------------
   Status  InitQueue(SqQueue &Q)
    {
    //构造一个空队列Q
          Q.base = (QElemType *)malloc(MAXQSIZE*sizeof(QElemType));
           if(!Q.base)exit(OVERFLOW);
           Q.front = Q.rear;
            return OK;
    }

    int  QueueLength(SqQueue Q)
    {
     //返回队列元素的个数,即队列的长度
         
        return(Q.rear - Q.front + MAXQSIZE) % MAXQSIZE;
    }

    Status  EnQueue(SqQueue &Q, QElemType e)
    {
     //插入元素e到队列尾
          if((Q.rear + 1) % MAXQSIZE == Q.front) return ERROR;       //队列满
          Q.base[Q.rear] = e; 
          Q.rear = (Q.rear + 1) % MAXQSIZE;
          return OK;
    }

    Status  DeQueue(SqQueue &Q, QElemType &e)
    {
    //删除队列头元素,用e返回
         if(Q.front == Q.rear) return ERROR;
         e = Q.base[Q.front];
         Q.front = (Q.front + 1) % MAXQSIZE;
         return OK;
    }

    


























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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值