1.基本概念
队列(
Queue
):也是运算受限的线性表。是一种先进先出(
First In First Out
,简称
FIFO
)的线性表。只允许在表的一端进行插入,而在另一端进行删除。
队首(
front
) :允许进行删除的一端称为队首;
队尾(
rear
) :允许进行插入的一端称为队尾;
在空队列中依次加入元素
a1, a2,
…
, an
之后,
a1
是队首元素,
an
是队尾元素。显然
退出队列的次序也只能是
a1, a2,
…
, an
,即队列的修改是依先进先出的原则进行的,如
图所示
队列的抽象数据类型定义
ADT Queue{
数据对象:D ={ a
i
|a
i
∈
ElemSet, i=1, 2,
…
, n, n >= 0 }
数据关系:R = {<a
i-1
, a
i
> | a
i-1
, a
i
∈
D, i=2,3,
…
,n }
约定 a1
端为队首,
a
n
端为队尾。
基本操作:
Create
():创建一个空队列;
EmptyQue
():若队列为空,则返回
true
,否则返回
flase
;
InsertQue
(x) :向队尾插入元素
x
;
DeleteQue
(x) :删除队首元素
x
;
} ADT Queue
2.顺序队列
利用一组连续的存储单元(一维数组) 依次存放从队首到队尾的各个元素,称为顺
序队列。
静态顺序队列,其类型定义如下:
#define MAX_QUEUE_SIZE 100
typedef struct{
int data[MAX_QUEUE_SIZE];
int front;//队首指针
int rear;//队尾指针
}SqQueue;
约定: front始终指向队首元素
rear始终指向队尾元素的下一个空位置
初始化:
front = rear = 0
入队:将新元素插入
rear
所指的位置,然后
rear
加
1
。
出队:删去
front
所指的元素,然后加
1
并返回被删元素。
顺序队列中存在“假溢出”现象。尽管队列中实际元素个
数可能远远小于数组大小,但可能由于尾指针巳超出向量空间
的上界而不能做入队操作。该现象称为假溢出。
为充分利用空间,克服上述“假溢出”现象的方法是:将
为队列分配的向量空间看成为一个首尾相接的圆环,并称这种
队列为循环队列
入队:
rear
=
(
rear + 1
)
% MAX_QUEUE_SIZE
出队:
front =
(
front + 1
)
% MAX_QUEUE_SIZE
循环队列中元素个数:
len =
(
rear
–
front + MAX_QUEUE_SIZE
)
% MAX_QUEUE_SIZE
#define MAX_QUEUE_SIZE 100
typedef struct{
int data[MAX_QUEUE_SIZE];
int front;//队首指针
int rear;//队尾指针
}SqQueue;
/**
* 约定:front始终指向队首元素
* rear始终指向队尾元素的下一个空位置
*/
SqQueue create_queue() {
SqQueue queue;
queue.front = 0;
queue.rear = 0;
return queue;
}
//将数据元素 e 插入到循环队列 Q 的队尾
bool insert_queue(SqQueue* q, int e) {
//判断队列是否满
if ((q->rear + 1) % MAX_QUEUE_SIZE == q->front) {
return false;
}
q->data[q->rear] = e;
q->rear = (q->rear + 1) % MAX_QUEUE_SIZE;
return true;
}
//将循环队列 Q 的队首元素出队
bool delete_queue(SqQueue* q, int *e) {
//先判断队列是否空
if (q->rear == q->front) {
return false;
}
*e = q->data[q->front];
q->front = (q->front + 1) % MAX_QUEUE_SIZE;
return true;
}
int delete_queue(SqQueue* q) {
int e;
bool ok = delete_queue(q, &e);
return e;
}
int length(const SqQueue* q) {
return (q->rear - q->front + MAX_QUEUE_SIZE) % MAX_QUEUE_SIZE;
}
bool empty(const SqQueue* q) {
return q->front == q->rear;
}
bool full(const SqQueue* q) {
return q->front == (q->rear+1)%MAX_QUEUE_SIZE;
}
void test1() {
SqQueue q = create_queue();
for (int i = 1; i <= 10; i++) {
insert_queue(&q, i*2);
}
for (int i = 1; i <= 3; i++) {
printf("%d,", delete_queue(&q));//2,4,6
}
printf("\n=============\n");
printf("len = %d\n", length(&q));//7
printf("\n=============\n");
SqQueue q1 = create_queue();
printf("empty ? %s\n", empty(&q1) ? "true" : "false");//true
printf("full ? %s\n", full(&q1) ? "true" : "false");//false
printf("\n=============\n");
SqQueue q2 = create_queue();
for (int i = 0; i < MAX_QUEUE_SIZE; i++) {
insert_queue(&q2, i);
}
printf("empty ? %s\n", empty(&q2) ? "true" : "false");//false
printf("full ? %s\n", full(&q2) ? "true" : "false");//true
}
3.链式队列
队列的链式存储结构简称为链队列,它是限制仅在表头进行删除操作和表尾进行插入
操作的单链表。
数据元素结点类型定义:
typedef struct QNode {
int data;
struct QNode* next;
}QNode;
typedef struct{
QNode* front;
QNode* rear;
}LinkQueue;
链队的操作实际上是单链表的操作,只不过是删除在表头进行,插入在表尾进行。插
入、删除时分别修改不同的指针。
typedef struct QNode {
int data;
struct QNode* next;
}QNode;
typedef struct{
QNode* front;
QNode* rear;
}LinkQueue;
/**
* 创建结点(私有函数)
*/
QNode* node_create(int data, QNode *next) {
QNode* node = (QNode*)malloc(sizeof(QNode));
if (node != nullptr) {
node->data = data;
node->next = next;
}
return node;
}
/**
* 创建链队列
*/
LinkQueue queue_create() {
LinkQueue q;
q.front = node_create(0, nullptr);
q.rear = q.front;
return q;
}
bool insert_queue(LinkQueue* q, int e) {
if (q == nullptr || q->front == nullptr) {
return false;
}
//创建结点,插入队列尾
QNode* node = node_create(e, nullptr);
q->rear->next = node;
q->rear = node;
return true;
}
bool delete_queue(LinkQueue* q, int* e) {
if (q == nullptr || q->front == nullptr) {
return false;
}
if (q->front == q->rear) {//队列为空,返回false
return false;
}
QNode* p = q->front->next;
q->front->next = p->next;
*e = p->data;
free(p);
return true;
}
int delete_queue(LinkQueue* q) {
int e;
if (false == delete_queue(q, &e)) {
return INT_MIN;
}
return e;
}
bool empty(LinkQueue* q) {
return q->front == q->rear;
}
void test() {
LinkQueue q = queue_create();
for (int i = 1; i <= 10; i++) {
insert_queue(&q, i * i);
}
for (int i = 1; i <= 10; i++) {
printf("%d,", delete_queue(&q));
}
printf("\n=============\n");
}
4.队列应用
1. 排队买东西
、打印机服务、医院的挂号系统等等
2. 树的层次遍历
3. 图的广度优先遍历