基本数据结构 -- 队列(数组实现)
队列是一种先进先出(FIFO)的线性表。对队列的基本操作有两种: 入队(Enqueue),在表的末端(队尾 tail)插入一个元素;出队(Dequeue),删除或返回在表的开头(队头 head)的元素。本文介绍如何使用数组在 C 语言中实现一个队列,平台为VS2010。
先创建一个队列结构体,这个结构体应该包括这几个元素:队头在数组中的位置(Front)、队尾在数组中的位置(Rear)、队列的大小(Size)、用于存储队列的数组(Array)以及数组的容量(Capacity):
typedef int ElementType; struct QueueRecord { int Capacity; // 数组容量 int Front; // 队头的位置 int Rear; // 队尾的位置 int Size; // 队列大小 ElementType *Array; // 用于存放队列的数组 }; typedef struct QueueRecord Queue; typedef struct QueueRecord *PtrToQueue;
一、创建队列
使用前面的结构体来创建一个队列:
PtrToQueue CreateQueue(int capacity) { PtrToQueue queue = (PtrToQueue )malloc(sizeof(Queue)); if (queue == NULL) { perror("malloc failed!\n"); exit(EXIT_FAILURE); } queue->Capacity = capacity; queue->Array = (ElementType *)malloc(sizeof(ElementType) * capacity); MakeEmpty(queue); return queue; } void MakeEmpty(PtrToQueue Q) { Q->Size = 0; // 队列长度设为1 Q->Front = 1; // 队头位置为 1 Q->Rear = 0; // 队尾位置为 0 }
二、入队操作
向指定队列的尾部插入一个元素,即为入队操作。在每次插入之前都要判断队列是否还有空间供新元素插入。
void Enqueue(PtrToQueue Q,ElementType element) { if (IsFull(Q)) { perror("队列已满,入队失败\n"); exit(EXIT_FAILURE); } else { Q->Size++; // 队列大小加 1 if (++Q->Rear == Q->Capacity) { Q->Rear = 0; } Q->Array[Q->Rear] = element; } } bool IsFull(PtrToQueue Q) { return Q->Size == Q->Capacity; }
在入队操作中,设置了一个循环数组,在队尾位置要超出数组边界时,将队尾放到数组开始处,以便最大利用数组空间。
三、出队操作
将队列的队头元素从队列中删除,对于数组队列,只需要将队头位置加 1 即可。
void Dequeue(PtrToQueue Q) { if (IsEmpty(Q)) { perror("队列为空,无法执行出队操作\n"); exit(EXIT_FAILURE); } else { Q->Size--; // 队列大小减 1 if (++Q->Front == Q->Capacity) { Q->Front = 0; } } } bool IsEmpty(PtrToQueue Q) { return Q->Size == 0; }
同样的,为了最大利用数组空间,出队操作也使用了循环数组。
四、遍历队列
从队头元素开始遍历整个队列:
void TraverseQueue(PtrToQueue Q) { if (Q->Size == 0) { printf("队列为空\n"); } for (int i = 0; i < Q->Size; i++) { if (Q->Front + i < Q->Capacity) { printf("%d ", Q->Array[Q->Front + i]); } else { printf("%d ", Q->Array[Q->Front + i - Q->Capacity]); } } }
五、完整代码
#include <stdio.h> #include <stdlib.h> typedef int ElementType; struct QueueRecord { int Capacity; // 数组容量 int Front; // 队头的位置 int Rear; // 队尾的位置 int Size; // 队列大小 ElementType *Array; // 用于存放队列的数组 }; typedef struct QueueRecord Queue; typedef struct QueueRecord *PtrToQueue; PtrToQueue CreateQueue(int capacity); void MakeEmpty(PtrToQueue Q); void Enqueue(PtrToQueue Q, ElementType element); void Dequeue(PtrToQueue Q); bool IsFull(PtrToQueue Q); bool IsEmpty(PtrToQueue Q); void TraverseQueue(PtrToQueue Q); ElementType Peek(PtrToQueue Q); int main() { PtrToQueue newQueue = CreateQueue(10); // 创建一个空队列 for (int i = 0; i < 10; i++) { Enqueue(newQueue,i); // 向队列中添加元素 } TraverseQueue(newQueue); // 遍历队列 Dequeue(newQueue); // 出队 Dequeue(newQueue); // 出队 TraverseQueue(newQueue); Enqueue(newQueue, 50); // 入队 TraverseQueue(newQueue); return 0; } // 创建一个队列 PtrToQueue CreateQueue(int capacity) { PtrToQueue queue = (PtrToQueue )malloc(sizeof(Queue)); if (queue == NULL) { perror("malloc failed!\n"); exit(EXIT_FAILURE); } queue->Capacity = capacity; queue->Array = (ElementType *)malloc(sizeof(ElementType) * capacity); MakeEmpty(queue); return queue; } void MakeEmpty(PtrToQueue Q) { Q->Size = 0; Q->Front = 1; Q->Rear = 0; } // 入队 void Enqueue(PtrToQueue Q,ElementType element) { if (IsFull(Q)) { perror("队列已满,入队失败\n"); exit(EXIT_FAILURE); } else { Q->Size++; if (++Q->Rear == Q->Capacity) { Q->Rear = 0; } Q->Array[Q->Rear] = element; } } // 出队 void Dequeue(PtrToQueue Q) { if (IsEmpty(Q)) { perror("队列为空,无法执行出队操作\n"); exit(EXIT_FAILURE); } else { Q->Size--; if (++Q->Front == Q->Capacity) { Q->Front = 0; } } } // 判断队列是否为满 bool IsFull(PtrToQueue Q) { return Q->Size == Q->Capacity; } // 判断队列是否为空 bool IsEmpty(PtrToQueue Q) { return Q->Size == 0; } // 遍历队列 void TraverseQueue(PtrToQueue Q) { if (Q->Size == 0) { printf("队列为空\n"); } for (int i = 0; i < Q->Size; i++) { if (Q->Front + i < Q->Capacity) { printf("%d ", Q->Array[Q->Front + i]); } else { printf("%d ", Q->Array[Q->Front + i - Q->Capacity]); } } printf("\n"); } // 获取队头元素 ElementType Peek(PtrToQueue Q) { return Q->Array[Q->Front]; }
这段代码创建了一个队列,将整数 0~9分别入队,然后执行两次出队操作,再将整数 50 入队,程序执行结果如下:
参考资料:
《数据结构与算法分析 -- C语言描述》