数据结构:用数组实现队列(Implementing Queue Using Array)

目录

第1步:设计蓝图 (The Struct)

第2步:队列的诞生 (创建与初始化)

第3步:状态检查 (判满与判空)

第4步:核心操作 (入队与出队)

入队 (Enqueue)

出队 (Dequeue)

第5步:善后工作 (销毁队列)


现在,我们聚焦于如何用代码一步步地实现这个最终方案。我们从零开始,只写必要的代码,并在每一步都解释为什么这么写。

数据结构:队列(Queue)与循环队列(Circular Queue)-CSDN博客


第1步:设计蓝图 (The Struct)

从第一性原理出发,要描述一个队列,我们需要知道哪些信息?

  1. 数据存放在哪里? -> 需要一个指针指向我们的数据区。 (int* data)

  2. 队列的总容量是多少? -> 需要一个变量记录容量,这样我们的取模运算才有依据。 (int capacity)

  3. 队头在哪里? -> 需要一个下标作为队头指针。 (int front)

  4. 队尾在哪里? -> 需要一个下标作为队尾指针。 (int rear)

把这些信息组合起来,就形成了我们的“蓝图”——结构体定义。

【代码实现 1:结构体定义】

#include <stdio.h>
#include <stdlib.h> // 我们需要用 malloc 和 free 来动态管理内存// 循环队列的蓝图
typedef struct {int* data;      // 指向一块用于存储数据的内存int capacity;   // 这块内存的总容量 (实际能存的元素数是 capacity-1)int front;      // 队头元素的下标int rear;       // 队尾元素的下一个位置的下标
} CircularQueue;

这就像建房子前画的设计图,它定义了我们的队列由哪几部分构成。


第2步:队列的诞生 (创建与初始化)

有了蓝图,我们就可以“施工”了,即创建一个具体的队列实例。创建一个容量为 k 的队列,需要做什么?

  1. CircularQueue 这个结构体本身分配一块内存。

  2. data 指针指向的数组分配一块内存。根据我们的最终方案,要存储 k 个元素,需要 k+1 的数组空间。

  3. 设置初始状态。一个空队列的初始状态是什么?根据我们的约定,是 frontrear 相等。最简单的就是都设为 0。

【代码实现 2:创建队列函数】

// 功能:创建一个能容纳 k 个元素的空队列
CircularQueue* createQueue(int k) {// 1. 为队列的整体结构分配内存CircularQueue* q = (CircularQueue*)malloc(sizeof(CircularQueue));// 防御性编程:检查内存是否分配成功if (!q) {perror("Failed to allocate memory for queue structure");return NULL;}// 2. 设置容量。注意,我们需要 k+1 个空间q->capacity = k + 1;// 3. 为实际存储数据的数组分配内存q->data = (int*)malloc(q->capacity * sizeof(int));// 再次进行防御性编程if (!q->data) {perror("Failed to allocate memory for queue data");free(q); // 如果数据区分配失败,必须释放之前为结构体分配的内存,防止内存泄漏return NULL;}// 4. 初始化头尾指针,表示队列为空q->front = 0;q->rear = 0;// 5. 返回创建好的队列实例return q;
}

第3步:状态检查 (判满与判空)

在进行核心操作(入队/出队)之前,必须先能准确判断队列的状态。这就像开车前要先看油表和仪表盘。

  • 判空 (isEmpty): 我们的约定是 front == rear

  • 判满 (isFull): 我们的约定是队尾的下一个位置是队头,即 (rear + 1) % capacity == front

这些是实现后续功能的基石。

【代码实现 3:状态判断函数】

// 功能:判断队列是否为空
int isEmpty(CircularQueue* q) {// 直接翻译我们的约定: front 等于 rearreturn q->front == q->rear;
}// 功能:判断队列是否为满
int isFull(CircularQueue* q) {// 直接翻译我们的约定: (rear + 1) 对 capacity 取模后等于 frontreturn (q->rear + 1) % q->capacity == q->front;
}

这两个函数非常简洁,但它们是整个循环队列逻辑的核心。


第4步:核心操作 (入队与出队)

现在,万事俱备,我们可以实现队列的两个核心灵魂操作了。

入队 (Enqueue)

要将一个值 value 加入队尾,需要三步:

  1. 检查:队列是不是已经满了?如果满了,就不能再入了。这是操作的“前置条件”。

  2. 放置:如果没满,就把 value 放到 rear 指向的位置。

  3. 更新rear 指针需要向前移动一位,为下一次入队做准备。别忘了,要用取模运算来实现循环。

【代码实现 4:入队函数】

// 功能:将一个元素 value 加入队尾
int enqueue(CircularQueue* q, int value) {// 1. 前置条件检查if (isFull(q)) {printf("入队失败:队列已满。\n");return 0; // 返回 0 表示失败}// 2. 放置数据q->data[q->rear] = value;// 3. 更新队尾指针,使用取模运算实现循环q->rear = (q->rear + 1) % q->capacity;return 1; // 返回 1 表示成功
}

出队 (Dequeue)

要从队头取出一个元素,逻辑类似:

  1. 检查:队列是不是空的?如果是空的,就无元素可取。这是操作的“前置条件”。

  2. 取出:如果没空,就从 front 指向的位置获取元素值。

  3. 更新front 指针需要向前移动一位,指向新的队头。同样,要用取模运算。

【代码实现 5:出队函数】

// 功能:从队头取出一个元素,并通过指针 pValue 返回该元素的值
int dequeue(CircularQueue* q, int* pValue) {// 1. 前置条件检查if (isEmpty(q)) {printf("出队失败:队列为空。\n");return 0; // 失败}// 2. 取出数据*pValue = q->data[q->front];// 3. 更新队头指针,使用取模运算实现循环q->front = (q->front + 1) % q->capacity;return 1; // 成功
}

第5步:善后工作 (销毁队列)

我们用 malloc 申请了内存,在程序结束前,作为一个负责任的程序员,必须将这些内存归还给操作系统,否则会造成内存泄漏。

销毁的顺序应该是:先释放内部的 data 数组,再释放队列结构体本身。

【代码实现 6:销毁函数】

// 功能:释放队列占用的所有内存
void destroyQueue(CircularQueue* q) {if (q != NULL) {// 1. 如果 data 指针有效,则先释放它指向的数组内存if (q->data != NULL) {free(q->data);}// 2. 再释放队列结构体本身的内存free(q);}
}

至此,我们已经从一张“蓝图”开始,一步步地构建了创建、检查、操作、销毁一个完整循环队列所需的所有代码。每一步的实现都紧密围绕着我们最初通过第一性原理推导出的核心约定。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/bicheng/93555.shtml
繁体地址,请注明出处:http://hk.pswp.cn/bicheng/93555.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Boost库核心组件与应用

一、BOOST 库简介&#xff1a;C 开发者的 “扩展工具集” 在 C 编程领域&#xff0c;除了标准库&#xff08;STL&#xff09;外&#xff0c;BOOST 库是最具影响力的第三方库之一。它由全球数百位开发者共同维护&#xff0c;包含超过 160 个高质量的组件&#xff0c;覆盖从基础…

机器学习 [白板推导](十二)[卡曼滤波、粒子滤波]

15. 线性动态系统&#xff08;卡曼滤波&#xff0c;Kalman Filter&#xff09; 15.1. 概述 15.1.1. 背景介绍 变量随时间变化的系统叫做动态系统&#xff0c;其中隐变量取值离散的是隐马尔可夫模型&#xff08;HMM&#xff09;&#xff0c;而隐变量取值连续的分为线性动态系统…

RH134 访问网络附加存储知识点

1. NFS 的主要功能是什么&#xff1f;答&#xff1a;NFS是一种分布式文件系统协议&#xff0c;主要功能包括&#xff1a;允许远程计算机通过网络访问共享文件。 实现文件系统在客户端和服务器之间的透明访问。支持文件的共享、读取和写入&#xff0c;使得多个 …

组合模式及优化

组合模式是一种结构型设计模式&#xff0c;其核心思想是将对象组合成树形结构&#xff0c;以表示“部分-整体”的层次关系&#xff0c;使得用户对单个对象和组合对象的使用具有一致性。 一、介绍 核心角色 组合模式包含以下3个关键角色&#xff1a; 抽象组件&#xff08;Compon…

【wmi异常】关于taskkill命令提示“错误:找不到” 以及无法正常获取设备机器码的处理办法

记录一下我的解决方案。 我先查阅了这篇博客&#xff1a;https://blog.csdn.net/qq_45698181/article/details/138957277 发现他写的批处理不知怎么执行不了&#xff0c;后来问了ai又可以执行了&#xff0c;估计是csdn防盗版格式问题 这里写一下我跟ai的对话&#xff0c;大家可…

制造装配、仓储搬运、快递装卸皆适配!MinkTec 弯曲形变传感器助力,让人体工学改变劳动生活

【导语】Minktec 最新实验显示&#xff1a;将Minktec 柔性弯曲形变传感器FlexTail 贴于受试者背部&#xff0c;记录 1 分钟内从洗碗机取餐具的动作&#xff0c;结合配套的flexlib -专用Python库分析&#xff0c;不仅量化出 “越低越伤腰” 的结论&#xff0c;更为制造装配、物流…

Nginx蜘蛛请求智能分流:精准识别爬虫并转发SEO渲染服务

> 一招解决搜索引擎爬虫无法解析现代前端框架的痛点,提升网站收录率与SEO排名! **痛点场景**:你的网站采用Vue/React等前端框架构建,页面内容依赖JavaScript动态渲染。搜索引擎爬虫访问时,只能抓取到空HTML骨架,无法获取真实内容,导致网站收录率低、SEO效果差。 --…

链表。。。

目录 5.1 链表的结点 5.2 插入 5.3 链表长度 5.4 查找 5.5 指定位置删除 5.6 代码 5.1 链表的结点 一个结点包括&#xff1a;值和指向下一个结点的指针。 package com.qcby.链表;public class Node {int value;Node next;public Node(int val){valueval;}Overridepublic…

私人AI搜索新突破:3步本地部署Dify+Ollama+QwQ,搜索能力MAX

1.安装Docker容器 本地部署Dify要先安装Docker桌面版&#xff0c;跟Ollama一样简单&#xff0c;也是去官网下载对应版本文件&#xff0c;直接安装就OK。 2&#xff1a;安装Dify 安装 Dify 简单的方式就是git clone&#xff0c;复制其github地址github.com/langgenius/dify&am…

(2-10-1)MyBatis的基础与基本使用

目录 0.前置小节 1. MyBatis 框架介绍 1.1 软件开发中的框架 1.2 使用框架的好处 1.3 SSM 开发框架 1.4 什么是 MyBatis 1.5 MyBatis 的开发流程 2. MyBatis 的开发流程 2.0 MyBatis的工作流程 2.1 引入 MyBatis 依赖 00.base(目录、pom、单元测试、Junit4) 01.Cal…

StarRocks集群部署

Starrocks 是一款基于 MPP 架构的高性能实时分析型数据库&#xff0c;专为 OLAP&#xff08;联机分析处理&#xff09;场景 设计&#xff0c;尤其擅长处理海量数据的实时分析、复杂查询和多维统计。 硬件 CPU&#xff1a;StarRocks依靠AVX2指令集充分发挥其矢量化能力。因此&am…

【CPP】自己实现一个CPP小工具demo,可以扩展其他选项

自己写CPP脚本小工具1. 思路描述2. 代码实现2.1 代码文件CppTool.cpp2.2 CMakeLists.txt3. 工具示例3.1 帮助信息3.2 工具用法3.3 实际使用1. 思路描述 实现一个简单的命令行工具。内容包括&#xff1a; 命令帮助信息参数检查&#xff0c;参数解析等功能。执行其他命令。将指…

如何使用嵌入模型创建本地知识库Demo

为data目录下的txt文档用阿里百炼的文本嵌入模型创建一个本地知识库import os from llama_index.core import ,Settings, SimpleDirectoryReader, VectorStoreIndex from llama_index.core.node_parser import SentenceSplitter from llama_index.llms.dashscope import DashSc…

SpringBoot 整合 Langchain4j:系统提示词与用户提示词实战详解

> 掌握提示词工程的核心技巧,让你的AI应用效果提升300%! **真实痛点**:为什么同样的模型,别人的应用精准专业,而你的却答非所问?关键在于提示词工程!本文将揭秘如何通过系统提示词与用户提示词的巧妙配合,打造专业级AI应用。 --- ### 一、Langchain4j 核心概念…

Sklearn 机器学习 邮件文本分类 加载邮件数据

💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Sklearn 机器学习 邮件文本分类 - 加载邮件数据 在自然语言处理(NLP)中,邮件文本分…

腾讯云开发小程序工具箱使用心得

一、核心优势与使用体验 作为首批使用腾讯云开发&#xff08;CloudBase&#xff09;工具箱的开发者&#xff0c;我深刻感受到其通过CloudBase AI与MCP服务重构开发范式的创新价值。结合微信小程序开发场景&#xff0c;该平台在以下维度表现突出&#xff1a; 1. AI驱动的全栈开发…

机械加工元件——工业精密制造的璀璨明珠

在工业制造的宏大画卷中&#xff0c;机械加工元件犹如璀璨的明珠&#xff0c;以其卓越的性能和精湛的工艺&#xff0c;为各行各业的发展注入了源源不断的动力。它们虽形态各异&#xff0c;功能不同&#xff0c;却在无数产品中携手合作&#xff0c;展现出科技与柔性的完美融合。…

【八股】Redis-中小厂精要八股

Redis 基础 redis为什么这么快 (高) [!NOTE] 最首要的是Redis是纯内存操作, 比磁盘要快3个数量级同时在与内存操作中采用了非阻塞I/O多路复用机制来提高并发量并且基于Redis的IO密集型&#xff0c;采用单线程操作, 免去了线程切换开销Redis 内置了多种优化过后的数据结构实现…

C++字符串(string)操作解析:从基础到进阶

1. 字符串基础&#xff1a;大小与容量cppvoid test1() {string s1("Hello World");cout << "size : " << s1.size() << endl; // 输出字符串长度cout << "capacity " << s1.capacity() << endl; // 输出字…

蘑兔音乐:音乐创作的魔法棒

在这个充满创意与可能的时代&#xff0c;人人都有一颗渴望表达音乐之心。但传统音乐创作&#xff0c;复杂的乐理、昂贵的设备&#xff0c;总让人望而却步。别担心&#xff01;蘑兔 AI 音乐强势来袭&#xff0c;它就是那个能让音乐小白也能搞创作的神奇工具&#xff01;​灵感模…