队列的概念
- 队列(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;
}