队列的模拟实现

队列的模拟实现


文章目录

  • 队列的模拟实现
    • 前言
    • 一、队列的基本原理
      • 1)队列的定义
      • 2)队列的特性
      • 3)队列的应用场景
    • 二、模拟实现STL中队列的功能
      • 1)设计数据结构
      • 2)初始化队列(QueueInit)
      • 3)入队操作(QueuePush)
      • 4)出队操作(QueuePop)
      • 5)判空操作(QueueIs_empty)
      • 6)获取队列大小(QueueSize)
      • 7)获取队首和队尾元素(QueueFront,QueueBack)
      • 8)销毁队列(QueueDestory)
    • 三、测试队列
    • 总结

前言

​ 在程序设计中,数据结构是不可或缺的基础,而STL(Standard Template Library)作为C++中的重要组成部分,提供了丰富的数据结构和算法。本篇博客将带领大家一起深入探讨如何用C语言模拟实现STL中队列的所有功能。


一、队列的基本原理

1)队列的定义

队列是一种先进先出(FIFO)的数据结构,类似于现实生活中排队的场景。在队列中,新元素被添加到队尾,而只有队首的元素才能被移除。

2)队列的特性

队列的主要特性包括入队、出队、判空、获取大小、获取队首和队尾元素等操作。这些操作构成了队列的基本功能,我们将通过C语言实现这些功能,并详细解析代码。

3)队列的应用场景

队列在计算机科学中有着广泛的应用,例如任务调度、缓冲区管理、广度优先搜索等。深入了解队列的基本原理有助于我们更好地应用它解决实际问题。

二、模拟实现STL中队列的功能

对照STL中 queue 的特性实现各个功能函数:

在这里插入图片描述

1)设计数据结构

​ 我们将使用两个结构体 QNodeQueue ,来构建队列。QNode表示队列中的节点,而Queue则是队列本身,包含队首、队尾指针以及队列大小。

​ 首先声明该队列由单链表实现,由于需要首尾同时低时间复杂度操作,所以在避免双向循环链表的空间浪费前提下选择了单链表实现,同时为了首尾以O(1)操作特别添加了指向队列(单链表)首尾的指针。

typedef int QNodeType;typedef struct QNode
{QNodeType val;struct QNode* next;
}QNode;typedef struct Queue
{QNode* front;QNode* tail;size_t size;
}Queue;

2)初始化队列(QueueInit)

QueueInit 函数中,我们将队首、队尾指针初始化为NULL,队列大小初始化为0。

void QueueInit(Queue* q)
{assert(q);q->front = NULL;q->tail = NULL;q->size = 0;
}

3)入队操作(QueuePush)

QueuePush 函数负责将新元素入队。我们通过动态分配内存创建一个新节点,根据队列是否为空选择更新队首或队尾指针,并增加队列大小。

void QueuePush(Queue* q, QNodeType x)
{assert(q);QNode* node = (QNode*)malloc(sizeof(Queue));if (!node) { perror("QueuePush::malloc"); return; }node->next = NULL;node->val = x;if (q->size == 0){q->front = q->tail = node;}else{q->tail->next = node;q->tail = q->tail->next;}q->size++;
}

4)出队操作(QueuePop)

QueuePop 函数负责将队首元素出队。我们释放队首节点的内存,更新队首指针,并更新队列大小。特别注意,要避免单节点时删除头结点后,尾指针变为野指针的情况。

void QueuePop(Queue* q)
{assert(q);assert(q->size != 0);	// pop时保证队列非空QNode* tmp = q->front->next;free(q->front);      // 删除节点q->front = tmp;if (q->size == 1) { q->tail = NULL; }     // 避免单节点时删除头结点后,尾指针变为野指针q->size--;
}

5)判空操作(QueueIs_empty)

QueueIs_empty 函数用于判断队列是否为空,通过队列大小是否为0来实现。

bool QueueIs_empty(const Queue* q)
{assert(q);return (q->size == 0);
}

6)获取队列大小(QueueSize)

QueueSize 函数返回队列的大小。

size_t QueueSize(const Queue* q)
{assert(q);return q->size;
}

7)获取队首和队尾元素(QueueFront,QueueBack)

QueueFrontQueueBack 函数分别返回队列的队首和队尾元素值,确保队列非空。

QNodeType QueueFront(const Queue* q)
{assert(q);assert(q->size != 0);return q->front->val;
}QNodeType QueueBack(const Queue* q)
{assert(q);assert(q->size != 0);return q->tail->val;
}

8)销毁队列(QueueDestory)

QueueDestory 函数用于销毁队列,释放所有节点的内存。

void QueueDestory(Queue* q)
{assert(q);QNode* cur = q->front;while (cur){QNode* tmp = cur->next;free(cur);cur = tmp;}q->size = 0;
}

三、测试队列

测试代码:

void test()
{Queue q;QueueInit(&q);QueuePush(&q, 10);QueuePush(&q, 9);QueuePop(&q);QueuePush(&q, 8);QueuePush(&q, 7);QueuePush(&q, 6);QueuePop(&q);while (!QueueIs_empty(&q)){printf("%d\t", QueueFront(&q));printf("(%d)\t", QueueBack(&q));QueuePop(&q);}printf("\n");QueueDestory(&q);
}

运行结果:

在这里插入图片描述

功能测试结果与预期一致,同时并未发现内存泄漏,说明销毁队列也符合要求。


总结

​ 在实现队列的过程中,尤其注意逻辑成立的问题和程序鲁棒性增强,比如执行 QueuePop 操作时首先队列需非空,其次注意队列中只剩单个元素的情况下删除节点后记得安置尾指针,避免野指针存在的隐患。

​ 我们深入学习了队列的基本原理,并通过C语言实现了STL中队列的所有功能。我们详细解析了每个函数的实现细节,包括初始化、入队、出队等操作。队列作为一种重要的数据结构,在计算机科学中有着广泛的应用,对其深入了解有助于我们更好地解决实际问题。

​ 在实现队列的过程中,尤其注意逻辑成立的问题和程序鲁棒性增强,比如执行 QueuePop 操作时首先队列需非空,其次注意队列中只剩单个元素的情况下删除节点后记得安置尾指针,避免野指针存在的隐患。

​ 我们深入学习了队列的基本原理,并通过C语言实现了STL中队列的所有功能。我们详细解析了每个函数的实现细节,包括初始化、入队、出队等操作。队列作为一种重要的数据结构,在计算机科学中有着广泛的应用,对其深入了解有助于我们更好地解决实际问题。

在这里插入图片描述

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

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

相关文章

MySQL 中Relay Log打满磁盘问题的排查方案

MySQL 中Relay Log打满磁盘问题的排查方案 引言: MySQL Relay Log(中继日志)是MySQL复制过程中的一个重要组件,它用于将主数据库的二进制日志事件传递给从数据库。然而,当中继日志不断增长并最终占满磁盘空间时&…

Flutter:web项目跨域问题解决

前后端解决系列 文章目录 一、Flutter web客户端解决本地环境调试跨域问题二、Flutter web客户端解决线上环境跨域问题 一、Flutter web客户端解决本地环境调试跨域问题 就一句命令【--web-browser-flag "--disable-web-security"】,用来屏蔽浏览器域名请…

简单实现Spring容器(五) 实现bean后置处理器BeanPostProcessor机制

阶段5: // 1.编写自己的Spring容器,实现扫描包,得到bean的class对象. // 2.扫描将 bean 信息封装到 BeanDefinition对象,并放入到Map. // 3.初始化单例池并完成getBean() createBean()方法 // 4.完成依赖注入(如果创建某个Bean对象,存在依赖注入,需要进行bean组装操作) 5.bean…

城市基础设施智慧路灯改造的特点

智慧城市建设稳步有序推进。作为智慧城市的基础设施,智能照明是智慧城市的重要组成部分,而叁仟智慧路灯是智慧城市理念下的新产品。随着物联网和智能控制技术的飞速发展,路灯被赋予了新的任务和角色。除了使道路照明智能化和节能化外&#xf…

机器学习 类别特征编码:Category Encoders 库的使用

✅作者简介:人工智能专业本科在读,喜欢计算机与编程,写博客记录自己的学习历程。 🍎个人主页:小嗷犬的个人主页 🍊个人网站:小嗷犬的技术小站 🥭个人信条:为天地立心&…

使用WebyogSQLyog使用数据库

数据库 实现数据持久化到本地: 使用完整的管理系统统一管理, 数据库(DateBase): 为了方便数据存储和管理(增删改查),将数据按照特定的规则存储起来 安装WebyogSQLyog -- 创建数…

STP(生成树协议)

STP(生成树协议) 生成树协议原理: ​在二层交换网络中,逻辑的阻塞部分接口,实现从根节点到所有节点唯一的路径的生成,成为一个没有环路的拓扑。当最佳路径数显故障时,个别被阻塞的接口将被打开…

Slate基础使用说明

目录 Slate基础使用说明 1. 简单教程 2. 要点说明 2.1 TCommands以及TCommands基类 2.2 FUICommandInfo 2.3 FUICommandList 2.4 FUIAction 2.5 UICommand 3. 代码源码 4. 工具使用 4.1 Display Ul Extension Points 4. 参考文章 Slate基础使用说明 1.…

linux逻辑卷LVM

创建LVMVG管理LV扩容 6.2.6 逻辑卷LVM LVM是Logical Volume Manager 的简称,译为逻辑卷管理,它是Linux下对硬盘分区的一种管理机制。LVM适合于管理大存储设备,并允许用户动态调整文件系统的大小。此外,LVM的快照功能可以帮助我们快…

算法leetcode|92. 反转链表 II(rust重拳出击)

文章目录 92. 反转链表 II:样例 1:样例 2:提示:进阶: 分析:题解:rust:go:c:python:java: 92. 反转链表 II: 给你单链表的…

期待已久:K8S终于迎来交换内存Beta支持!

关注【云原生百宝箱】公众号,获取更多云原生消息 Kubernetes 1.22 版本开始支持在 Linux 节点上使用交换内存的 Alpha 特性,而在 1.28 版本中升级为 Beta 版本并进行了许多改进。之前版本的 Kubernetes 不支持 Linux 系统上的交换内存,但随着…

微信小程序、mpvue性能测试与体验

最近一直在折腾mpvue写的微信小程序的性能优化,分享下实战的过程。 先上个优化前后的图: 可以看到打包后的代码量从 813KB减少到 387KB,Audits体验评分从 B到 A,效果还是比较明显的。其实这个指标说明不了什么,而且轻易就可以做…