下面我将手把手教大家用C语言实现一个队列,从基础概念到完整代码,力求通俗易懂。
1. 队列的基本概念
队列是一种先进先出(FIFO,First In First Out)的数据结构。它类似于现实生活中的排队,比如排队买票,最早排队的人最先买到票。
队列的基本操作包括:
- 入队(Enqueue):在队列的尾部添加一个元素。
- 出队(Dequeue):从队列的头部移除一个元素。
- 查看队头元素(Peek/Front):查看队列头部的元素,但不移除它。
- 检查队列是否为空(IsEmpty):判断队列是否为空。
- 获取队列大小(Size):获取队列中的元素数量。
2. 使用数组实现队列
为了简单起见,我们先用数组来实现队列。数组实现的队列有一个缺点:出队操作会导致数组前面的位置被浪费。后续我们会介绍循环队列来解决这个问题。
定义队列结构
我们定义一个队列结构,包含数组、队头指针、队尾指针和队列大小。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAX_SIZE 100 // 队列的最大容量
typedef struct {
int data[MAX_SIZE]; // 存储队列元素的数组
int front; // 队头指针
int rear; // 队尾指针
int size; // 队列当前的大小
} Queue;
初始化队列
初始化队列时,将队头和队尾指针都设置为0,队列大小设置为0。
void initQueue(Queue* q) {
q->front = 0;
q->rear = 0;
q->size = 0;
}
入队操作
入队操作是将一个元素添加到队列的尾部。
bool enqueue(Queue* q, int value) {
if (q->size == MAX_SIZE) { // 检查队列是否已满
printf("Queue is full. Cannot enqueue.\n");
return false;
}
q->data[q->rear] = value; // 将元素添加到队尾
q->rear = (q->rear + 1) % MAX_SIZE; // 循环队列的特性
q->size++;
return true;
}
出队操作
出队操作是从队列的头部移除一个元素。
bool dequeue(Queue* q) {
if (q->size == 0) { // 检查队列是否为空
printf("Queue is empty. Cannot dequeue.\n");
return false;
}
q->front = (q->front + 1) % MAX_SIZE; // 移动队头指针
q->size--;
return true;
}
查看队头元素
查看队列头部的元素,但不移除它。
int front(Queue* q) {
if (q->size == 0) { // 检查队列是否为空
printf("Queue is empty. No front element.\n");
return -1; // 返回一个错误值
}
return q->data[q->front];
}
检查队列是否为空
判断队列是否为空。
bool isEmpty(Queue* q) {
return q->size == 0;
}
获取队列大小
获取队列中的元素数量。
int size(Queue* q) {
return q->size;
}
3. 完整代码示例
下面是一个完整的示例代码,展示如何使用上述队列操作。
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#define MAX_SIZE 100 // 队列的最大容量
typedef struct {
int data[MAX_SIZE]; // 存储队列元素的数组
int front; // 队头指针
int rear; // 队尾指针
int size; // 队列当前的大小
} Queue;
void initQueue(Queue* q) {
q->front = 0;
q->rear = 0;
q->size = 0;
}
bool enqueue(Queue* q, int value) {
if (q->size == MAX_SIZE) { // 检查队列是否已满
printf("Queue is full. Cannot enqueue.\n");
return false;
}
q->data[q->rear] = value; // 将元素添加到队尾
q->rear = (q->rear + 1) % MAX_SIZE; // 循环队列的特性
q->size++;
return true;
}
bool dequeue(Queue* q) {
if (q->size == 0) { // 检查队列是否为空
printf("Queue is empty. Cannot dequeue.\n");
return false;
}
q->front = (q->front + 1) % MAX_SIZE; // 移动队头指针
q->size--;
return true;
}
int front(Queue* q) {
if (q->size == 0) { // 检查队列是否为空
printf("Queue is empty. No front element.\n");
return -1; // 返回一个错误值
}
return q->data[q->front];
}
bool isEmpty(Queue* q) {
return q->size == 0;
}
int size(Queue* q) {
return q->size;
}
int main() {
Queue q;
initQueue(&q);
enqueue(&q, 10);
enqueue(&q, 20);
enqueue(&q, 30);
printf("Front element: %d\n", front(&q)); // 输出队头元素
printf("Queue size: %d\n", size(&q)); // 输出队列大小
dequeue(&q);
printf("Front element after dequeue: %d\n", front(&q)); // 输出队头元素
printf("Queue size after dequeue: %d\n", size(&q)); // 输出队列大小
return 0;
}
4. 输出结果
运行上述代码,输出结果如下:
Front element: 10
Queue size: 3
Front element after dequeue: 20
Queue size after dequeue: 2
5. 循环队列的改进
在上述实现中,队列满了之后,即使前面有空位,也无法再入队。为了充分利用数组空间,我们可以实现一个循环队列。
循环队列的关键在于如何判断队列是否已满。一个常见的方法是保留一个空位,即当rear追上front时,队列为空;当(rear + 1) % MAX_SIZE == front时,队列已满。
修改enqueue和dequeue函数如下:
bool enqueue(Queue* q, int value) {
if ((q->rear + 1) % MAX_SIZE == q->front) { // 检查队列是否已满
printf("Queue is full. Cannot enqueue.\n");
return false;
}
q->data[q->rear] = value; // 将元素添加到队尾
q->rear = (q->rear + 1) % MAX_SIZE; // 循环队列的特性
q->size++;
return true;
}
bool dequeue(Queue* q) {
if (q->front == q->rear) { // 检查队列是否为空
printf("Queue is empty. Cannot dequeue.\n");
return false;
}
q->front = (q->front + 1) % MAX_SIZE; // 移动队头指针
q->size--;
return true;
}
6. 总结
通过上述步骤,我们实现了队列的基本操作,并且介绍了如何改进为循环队列以充分利用数组空间。

933

被折叠的 条评论
为什么被折叠?



