C语言实现循环队列

C语言实现循环队列的完整攻略

前言

循环队列是一种常用的数据结构,用于解决队列数据访问时线性存储空间限制的问题。本文将讲解如何使用C语言实现循环队列。

队列的定义

队列是一种特殊的线性表,具有先进先出(FIFO)的特点,即最先进入队列的元素最先被取出。

循环队列的特殊之处在于,队列空间是使用连续的线性存储空间而形成的一个环。

循环队列的实现

代码实现

在C语言中,循环队列的实现可通过以下代码实现:

// 声明循环队列结构体
typedef struct {
    int* data;  // 指向队列数据域的指针
    int front;  // 队头指针
    int rear;   // 队尾指针
    int size;   // 队列大小
} CircularQueue;

// 初始化循环队列
CircularQueue* InitCircularQueue(int size) {
    CircularQueue* queue = (CircularQueue*)malloc(sizeof(CircularQueue));
    queue->data = (int*)malloc(sizeof(int) * size);
    queue->front = queue->rear = 0;
    queue->size = size;
    return queue;
}

// 判断循环队列是否为空
bool IsCircularQueueEmpty(CircularQueue* queue) {
    return queue->front == queue->rear;
}

// 判断循环队列是否已满
bool IsCircularQueueFull(CircularQueue* queue) {
    return (queue->rear + 1) % queue->size == queue->front;
}

// 往循环队列中添加元素
int AddCircularQueue(CircularQueue* queue, int value) {
    if (IsCircularQueueFull(queue)) {
        return -1;  // 队列已满,无法添加元素
    }
    queue->data[queue->rear] = value;
    queue->rear = (queue->rear + 1) % queue->size;
    return 0;
}

// 从循环队列中取出元素
int RemoveCircularQueue(CircularQueue* queue, int* value) {
    if (IsCircularQueueEmpty(queue)) {
        return -1;  // 队列为空,无法取出元素
    }
    *value = queue->data[queue->front];
    queue->front = (queue->front + 1) % queue->size;
    return 0;
}

// 销毁循环队列,释放内存空间
void DestroyCircularQueue(CircularQueue* queue) {
    free(queue->data);
    free(queue);
}

代码说明

上述代码中,定义了一个CircularQueue类型的结构体,其中包含了指向队列数据域的指针data,队头指针front,队尾指针rear,队列大小size四个成员。

接着,使用InitCircularQueue函数初始化循环队列,并在其中调用malloc函数分配数据空间,最后返回循环队列的指针。

在进行队列操作时,通过AddCircularQueue函数往队列中添加元素,通过RemoveCircularQueue函数将队列中的元素取出。

需要说明的是,为了避免“队尾指针指向数据空间的尾部而未满,队头指针指向数据空间的头部而为空”的歧义情况,循环队列中将队列的尾部指针(rear)指向下一个数据存放的位置。因此,判断队列是否为空的条件为队头指针(front)与队尾指针(rear)相等,而判断队列是否为满的条件为队列的下一位为队头指针(front)。

示例说明

示例1:使用循环队列解决Josephus问题

Josephus问题是一个著名的数学游戏,有N个人围成一圈,编号从1到N,从某个编号开始报数,数到M的人出列,之后从下一个人开始重新报数。求出最后留下的人的编号。

使用循环队列可以轻松地解决Josephus问题。下面是C语言实现代码及注释:

#include <stdio.h>
#include <stdlib.h>

// 声明循环队列结构体
#include "circlequeue.h"

int main() {
    int N = 10;   // 总人数
    int M = 3;    // 报数的周期
    int i, j;
    int e, a[N];  // 声明临时变量和数组
    CircularQueue* q;  // 声明循环队列指针
    q = InitCircularQueue(N);  // 初始化循环队列
    for (i = 0; i < N; i++) {
        AddCircularQueue(q, i + 1);  // 将人员编号依次加入队列
    }
    for (i = 0; i < N; i++) {
        RemoveCircularQueue(q, &e);  // 模拟报数,出队列
        a[i] = e;  // 将出队列的人员编号存放到数组中
        for (j = 1; j < M; j++) {
            RemoveCircularQueue(q, &e);  // 模拟报数,不出队列
            AddCircularQueue(q, e);      // 将不出队列的人员重新加入队列
        }
    }
    printf("出列顺序:");
    for (i = 0; i < N; i++) {
        printf("%d ", a[i]);  // 输出出列顺序
    }
    printf("\n最后留下:%d\n", e);  // 输出最后留下的人员编号
    DestroyCircularQueue(q);  // 删除队列,释放内存空间
    return 0;
}

示例2:使用循环队列模拟打印任务调度

使用循环队列可以方便地模拟打印任务的调度。下面是C语言实现代码及注释:

#include <stdio.h>
#include <stdlib.h>

// 声明循环队列结构体
#include "circlequeue.h"

int main() {
    int max_task_num = 6;   // 最大任务数
    int task_left = 0;      // 等待执行的任务数
    int executing_task_id;  // 当前正在执行的任务ID
    int i;
    CircularQueue* queue;   // 声明循环队列指针
    queue = InitCircularQueue(max_task_num);  // 初始化循环队列
    while (1) {
        printf("\n********************\n");      
        printf("等待任务:%d,", task_left);  // 打印等待任务数
        if (!IsCircularQueueEmpty(queue)) {
            printf("队列头部任务:[%d]\n", queue->data[queue->front]);  // 打印队列中最前面的任务
        } else {
            printf("无任务\n");  // 如果队列为空则输出“无任务”
        }
        printf("********************\n\n");      

        // 获取用户输入
        printf("请输入命令(a-添加任务,e-执行任务):");
        char cmd = getchar();
        while (getchar() != '\n')
            ;
        if (cmd == 'a') {  // 添加任务
            if (!IsCircularQueueFull(queue)) {
                AddCircularQueue(queue, max_task_num - task_left);  // 添加任务ID
                task_left++;  // 可执行任务数加1
                printf("添加成功,当前等待任务:%d\n", task_left);
            } else {
                printf("任务队列已满,无法添加任务\n");
            }
        } else if (cmd == 'e') {  // 执行任务
            if (!IsCircularQueueEmpty(queue)) {
                RemoveCircularQueue(queue, &executing_task_id);  // 取出队列中最前面的任务
                task_left--;  // 可执行任务数减1
                printf("任务[%d]开始执行,当前等待任务:%d\n", executing_task_id, task_left);
            } else {
                printf("任务队列为空,无法执行任务\n");
            }
        } else {
            printf("无效命令\n");
        }
    }
    DestroyCircularQueue(queue);  // 删除队列,释放内存空间
    return 0;
}

总结

本文介绍了C语言如何实现循环队列,包括定义循环队列结构体、初始化循环队列、判断队列是否为空、判断队列是否已满、往队列中添加元素、从队列中取出元素、销毁循环队列等操作。

同时,本文还提供了两个使用循环队列的示例:使用循环队列解决Josephus问题和使用循环队列模拟打印任务调度。这些示例可以帮助读者更好地理解和应用循环队列。

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C语言实现循环队列 - Python技术站

(0)
上一篇 2023年5月23日
下一篇 2023年5月23日

相关文章

  • Win10预览版19042升级后浏览器网页异常内容显示不全怎么办?

    对于Win10预览版19042升级后浏览器网页异常内容显示不全的情况,可能是因为升级过程中出现了一些问题导致系统出现了一些错误,或者是因为浏览器插件以及设置的问题所导致的。以下是处理该问题的完整攻略。 步骤一:更新浏览器插件 第一步需要检查浏览器是否有最新版本的插件可用,如果有,则需要更新插件以解决可能出现的兼容性问题。比如,用户在使用谷歌浏览器时,可以按照…

    C 2023年5月23日
    00
  • BYC币怎么样?BYC/币缘币还值得投资吗

    BYC币的基本概念 BYC币,全名为币缘币(Bytecoin),是一种匿名、去中心化、开源的数字货币。它于2012年创立,是第一代公开发行的隐私币之一。相比于比特币,BYC币主张保护交易者的隐私,并提供更快的交易确认速度和更低的交易费用。 BYC币的投资价值分析 优点 高度保护隐私:BYC币使用了加密技术和混淆账户的方法,可以有效保护交易者的个人隐私。 去中…

    C 2023年5月23日
    00
  • QT连接Mysql数据库的实现步骤

    好的。首先,我们需要安装 Qt 和 mysql 的相关驱动程序。安装完后,我们可以开始进行以下步骤: 步骤一:加载 mysql 驱动 在 Qt 中连接 mysql 数据库之前,我们需要在程序中先加载 mysql 驱动。在通常情况下,mysql 驱动是通过插件的方式来实现的。我们需要在项目的.pro 文件中加入以下代码: QT += sql QT += sql…

    C 2023年5月23日
    00
  • C 标准库 math.h

    首先我们来介绍一下 C 标准库 math.h。 math.h 是 C 标准库的一部分,提供了数学计算相关的函数。使用时需要在程序中包含 math.h 头文件。以下是部分常用的 math.h 函数: 基本数学函数 fabs(x):返回 x 的绝对值 sqrt(x):返回 x 的平方根 pow(x, y):返回 x 的 y 次幂 exp(x):返回 e 的 x …

    C 2023年5月10日
    00
  • 减少OpenCV读取高分辨率图像的时间示例

    下面是减少OpenCV读取高分辨率图像时间的完整攻略。 1. 问题背景 当读取高分辨率图像时,OpenCV可能需要较长的时间来加载和处理图像。这会导致我们无法快速地处理图像,例如进行实时图像处理等操作。因此,我们需要采取一些方法来减少OpenCV读取高分辨率图像的时间。 2. 解决方案 以下是减少OpenCV读取高分辨率图像的时间的解决方案: 方案一:降低图…

    C 2023年5月22日
    00
  • 拳皇97大门bug震的全人物整理

    拳皇97大门bug震的全人物整理攻略 什么是大门bug震? 在拳皇97中,存在一个被称为“大门bug”的漏洞。使用此漏洞可以通过特定按键组合让对手的活力值瞬间降为0,从而轻松获胜。而“大门bug震”则是一种利用此漏洞的特定攻击方式,使整个对手团队都受到震动效果,从而更容易实现胜利。 如何进行“大门bug震”? 要进行“大门bug震”,需要先使用一定的招数组合…

    C 2023年5月22日
    00
  • C++类与对象深入之引用与内联函数与auto关键字及for循环详解

    C++类与对象深入之引用与内联函数与auto关键字及for循环详解 引用 引用是C++中一种比指针更加方便的变量别名。引用可以看作一个已定义变量的别名,这个别名可以和变量一样访问其指向的对象。对引用进行读写操作,其实就是对原对象的读写操作。 使用引用的好处在于,它能够简化一些函数调用及赋值操作。在某些情况下,使用引用也能提高代码运行的效率。 引用的定义格式如…

    C 2023年5月22日
    00
  • C/C++ Linux Socket网络编程流程分析

    C/C++ Linux Socket网络编程流程分析 什么是Socket Socket是计算机网络中对于通信队列和编程接口的抽象。一句话概括,Socket是一种特殊的文件,它通过文件IO的方式向网络发送和接收数据。 Socket网络编程流程 创建Socket 创建一个Socket需要调用socket()函数,它有三个参数,分别是:地址族、类型、协议。在Lin…

    C 2023年5月23日
    00
合作推广
合作推广
分享本页
返回顶部