下面我将手把手教大家用C语言实现一个队列,从基础概念到完整代码,力求通俗易懂。

下面我将手把手教大家用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时,队列已满。

修改enqueuedequeue函数如下:

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. 总结

通过上述步骤,我们实现了队列的基本操作,并且介绍了如何改进为循环队列以充分利用数组空间。

#include #include #include //队列最大长度 #define MAX_QUEUE 1024 //偷懒,就用静态队列了 static int mQueue[MAX_QUEUE]; //队列插入 void InsertData(int **Front, int **Rear) { if (*Rear + 1 == *Front && (*Rear + 1 - MAX_QUEUE != *Front)) { //当队列数据已满,返回 puts("Queue Size Overflow!\n"); return; } else if (*Rear - mQueue > MAX_QUEUE) { //实现的是类似循环队列,但由于是静态线性队列(数组) //而不是用链表来实现的,所以到静态队列(数组)尾部,尾指针自动指向(数组)头部 *Rear = mQueue; } puts("Input Data:"); scanf("%d", *Rear); //输入数据后,尾指针后移 *Rear += 1; } //从头指针删除一个队列中的数据 void DeleteData(int **Front, int **Rear) { if (*Front == *Rear) { //头指针尾指针重合,队列空,不能删除,返回 puts("Queue Empty!\n"); return; } else if (*Front - mQueue > MAX_QUEUE) { //参考 Rear *Front = mQueue; } //从头指针删除一个数据 *Front += 1; } //显示队列数据 void ShowData(int **Front, int **Rear) { int *temp; for (temp=*Front; temp!=*Rear; temp++) { printf("%d --> ", *temp); } puts("\n"); } void usage(void) { puts("1. Insert Data"); puts("2. Delete Data"); puts("3. Show Data"); } int main(int argc, char **argv) { //头指针,尾指针 //队列一个特性 First in first out FIFO int *pFront, *pRear; int op_code; //初始化队列,头指针和尾指针此时指向的地址相同 pFront = pRear = mQueue; while (1) { usage(); scanf("%d", &op_code); switch (op_code) { case 1: printf("%p\n", pFront); printf("%d\n", *pFront); InsertData(&pFront, &pRear); break; case 2: DeleteData(&pFront, &pRear); break; case 3: ShowData(&pFront, &pRear); break; default: break; } } return 0; }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码力金矿

谢谢您的打赏,我将会更好创作。

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值