数据结构之队列


队列的基本概念
    队列(Queue):也是运算受限的线性表。是一种先进先出(First In First Out ,简称FIFO)的线性表。只允许在表的一端进行插入,而在另一端进行删除。
    队首(front) :允许进行删除的一端称为队首。
    队尾(rear) :允许进行插入的一端称为队尾。

 队列中没有元素时称为空队列。在空队列中依次加入元素a1, a2, …, an之后,a1是队首元素,an是队尾元素。显然退出队列的次序也只能是a1, a2, …, an ,即队列的修改是依先进先出的原则进行的。

队列的抽象数据类型定义
ADT Queue{
数据对象:D ={ ai|ai∈ElemSet,  i=1, 2, …, n, n >= 0 }

数据关系:R = {<ai-1, ai> | ai-1, ai∈D,  i=2,3,…,n }
       约定a1端为队首,an端为队尾。
基本操作:
Create():创建一个空队列;
EmptyQue():若队列为空,则返回true ,否则返回flase ;
⋯⋯
InsertQue(x) :向队尾插入元素x;
DeleteQue(x) :删除队首元素x;
} ADT Queue


 队列的顺序表示和实现:

      利用一组连续的存储单元(一维数组) 依次存放从队首到队尾的各个元素,称为顺序队列。
        对于队列,和顺序栈相类似,也有动态和静态之分。以下是静态顺序队列,其类型定义如下:
#define  MAX_QUEUE_SIZE   100
typedef  struct  queue
{  ElemType   Queue_array[MAX_QUEUE_SIZE] ;
int   front ;
int  rear ;
}SqQueue;


 队列的顺序存储结构:

设立一个队首指针front ,一个队尾指针rear ,分别指向队首和队尾元素。
 ◆ 初始化:front=rear=0。
 ◆ 入队:将新元素插入rear所指的位置,然后rear加1。
 ◆ 出队:删去front所指的元素,然后加1并返回被删元素。
 ◆ 队列为空:front=rear。
◆ 队满:rear=MAX_QUEUE_SIZE-1或front=rear。

 在非空队列里,队首指针始终指向队头元素,而队尾指针始终指向队尾元素的下一位置。
       顺序队列中存在“假溢出”现象。因为在入队和出队操作中,头、尾指针只增加不减小,致使被删除元素的空间永远无法重新利用。因此,尽管队列中实际元素个数可能远远小于数组大小,但可能由于尾指针巳超出向量空间的上界而不能做入队操作。该现象称为假溢出。如图3-6所示是数组大小为5的顺序队列中队首、队尾指针和队列中元素的变化情况。


循环队列:

为充分利用向量空间,克服上述“假溢出”现象的方法是:将为队列分配的向量空间看成为一个首尾相接的圆环,并称这种队列为循环队列(Circular Queue)。
        在循环队列中进行出队、入队操作时,队首、队尾指针仍要加1,朝前移动。只不过当队首、队尾指针指向向量上界(MAX_QUEUE_SIZE-1)时,其加1操作的结果是指向向量的下界0。
这种循环意义下的加1操作可以描述为:
if  (i+1==MAX_QUEUE_SIZE)   i=0;
else     i++ ;
其中: i代表队首指针(front)或队尾指针(rear)

用模运算可简化为:i=(i+1)%MAX_QUEUE_SIZE ;
        显然,为循环队列所分配的空间可以被充分利用,除非向量空间真的被队列元素全部占用,否则不会上溢。因此,真正实用的顺序队列是循环队列。

入队时尾指针向前追赶头指针,出队时头指针向前追赶尾指针,故队空和队满时头尾指针均相等。因此,无法通过front=rear来判断队列“空”还是“满”。解决此问题的方法是:约定入队前,测试尾指针在循环意义下加1后是否等于头指针,若相等则认为队满。即:
               ◆ rear所指的单元始终为空。

◆ 循环队列为空:front=rear 。  
◆ 循环队列满:(rear+1)%MAX_QUEUE_SIZE =front。


循环队列的基本操作
1 循环队列的初始化
SqQueue Init_CirQueue(void)
{  SqQueue  Q ;
Q.front=Q.rear=0;  return(Q) ;
}

入队操作
Status Insert_CirQueue(SqQueue  Q , ElemType  e)
  /*  将数据元素e插入到循环队列Q的队尾  */

 if  ((Q.rear+1)%MAX_QUEUE_SIZE== Q.front)
return  ERROR;      /*  队满,返回错误标志    */
Q.Queue_array[Q.rear]=e ;   /*  元素e入队  */
Q.rear=(Q.rear+1)% MAX_QUEUE_SIZE ; 
/*  队尾指针向前移动  */
return OK;        /*  入队成功    */
}

出队操作
Status Delete_CirQueue(SqQueue  Q, ElemType  *x )
   /*  将循环队列Q的队首元素出队  */

if  (Q.front+1== Q.rear)
return ERROR ;       /*  队空,返回错误标志    */
*x=Q.Queue_array[Q.front] ;  /* 取队首元素 */
Q.front=(Q.front+1)% MAX_QUEUE_SIZE ;
      /*  队首指针向前移动  */
return OK ;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值