四.队列

队列的概念

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

队列的抽象数据类型

ADT Queue{
数据对象:(D={a_i|a_i∈ElemSet,i=1,...,n,n≥0})
数据关系:(R={<a_{i-1},a_i>|a_{i-1},a_i∈D,i=2,3,...n})
约定(a_1)端为队首,(a_n)端为队尾。
基本操作:
Create():创建一个空队列;
EmptyQue():若队列为空,则返回true,否则返回false;
……
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

循环队列

为充分利用向量空间,克服“假溢出”现象的方法是:将为队列分配的向量空间看成为一个首尾相接的圆环,并称这种队列为循环队列(Circular Queue)。
在循环队列中进行出队、入队操作时,队首、队尾指针仍要加1,朝前移动。只不过当队首、队尾指针指向向量上界(MAX_QUEUE_SIZE )时,其加1操作的结果是指向向量的下界0。
这种循环意义下的加1操作可以描述为:i=(i+1)%MAX_QUEUE_SIZE
显然,为循环队列所分配的空间可以被充分利用,除非向量空间真的被队列元素全部占用,否则不会上溢。
因此,真正实用的顺序队列是循环队列。
1)rear所指的单元始终为空
2)循环队列为空:front=rear
3)循环队列满:(rear+1)%MAX_QUEUE_SIZE=front

  • 队列初始化
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;
}

队列的链式表示和实现

队列的链式存储表示

队列的链式存储结构简称为链队列,它是限制仅在表头进行删除操作和表尾进行插入操作的单链表。
需要两类不同的节点:数据元素节点,队列的队首指针和队尾指针的节点。

/*数据元素节点类型的定义:*/
typedef struct QNode
{ ElemType data; 
  struct QNode *next;    
}QNode;

/*指针结点类型的定义:*/
typedef struct link_queue
{ QNode *front,*rear;    
}Link_Queue;
  • 链队列的初始化
LinkQueue *Init_LinkQueue(void)
{  LinkQueue *Q;
   QNode *p;
   p=(QNode *)malloc(sizeof(QNode));/*开辟头结点*/
   p->next=NULL;
   Q=(LinkQueue *)malloc(sizeof(LinkQueue));/*开辟链队的指针结点*/
   Q.front=Q.rear=p;
   return(Q);
}
  • 入队操作
Status Insert_LinkQueue(LinkQueue *Q,ElemType e)
/*将数据元素e插入到链队列Q的队尾*/
{  p=(QNode *)malloc(sizeof(QNode));
   if(!p)
   return ERROR;/*申请新结点失败,返回错误标志*/
   p->data=e;
   p->next=NULL;/*形成新结点*/
   Q.rear->=p;
   Q.rear=p;/*新结点插入到队尾*/
   return OK;
}
  • 出队操作
Status Delete_LinkQueue(LinkQueue *Q,ElemType *x)
/*将循环队列Q的队首元素出队*/
{  QNode *p;
   if(Q.front==Q.rear)
   return ERROR;/*队空,返回错误标志*/
   p=Q.front->next;/*取队首结点*/
   *x=p->data;
   Q.front->next=p->next;/*修改队首指针*/
   if(p==Q.rear)
   Q.rear=Q.front
   /*当队列只有一个结点时应防止丢失队尾指针*/
   free(p);
   return OK;
}
原文地址:https://www.cnblogs.com/jianxiong0117/p/9437141.html