【C++】STL库_stack_queue 的模拟实现

news2025/4/8 18:21:12

       栈(Stack)、队列(Queue)是C++ STL中的经典容器适配器

容器适配器特性

  1. 不是独立容器,依赖底层容器(deque/vector/list)
  2. 通过限制基础容器接口实现特定访问模式
  3. 不支持迭代器操作(无法遍历元素)
  4. 时间复杂度:
    • 栈/队列操作均为O(1)
    • 底层容器影响性能:
      • vector实现栈可能导致扩容拷贝
      • list实现队列保证稳定性能

典型应用场景:

  • 栈:函数调用栈、括号匹配、表达式求值
  • 队列:消息队列、BFS算法、缓冲机制

(栈和队列前面C语言写过,这里直接贴C++代码)

双端队列:

 (不常用,简单介绍和理解)

STL标准库里面默认适配器使用的是deque这个容器,

    deque(双端队列)是C++标准库中的顺序容器,全称"double-ended queue",支持在头尾两端高效插入/删除元素。

         

  • 分段连续存储:由多个固定大小的存储块(称为缓冲区buffer)构成
  • 中控器结构:使用指针数组(map)管理存储块的地址

优势:

  • 任意位置(头尾插入)插入删除
  • 可以随机访问

缺陷:

  • operator[],计算稍显复杂,大量使用,性能下降。
  • 中间插入删除效率不高
  • 底层角度选代器会很复杂

cur 表示当前数据
first 和 last 表示 buffer 的开始和结束
node 反向指向中控位置,方便遍历时找下一个buffer

栈:

template<class T,class Container=deque<T>>
class stack
{
public:
	void push(const T& x)
	{
		_con.push_back(x);
	}

	void pop();

	T& top()
	{
		return _con.back();
	}

	bool empty()const
	{
		return _con.empty();
	}

	size_t size()
	{
		return _con.size();
	}


private:
	Container _con;

};

template<class T, class Container>
inline void stack<T, Container>::pop()
{
	_con.pop_back();
}

队列:

template<class T, class Container = deque<T>>
class queue
{
public:
	void push(const T& x);

	void pop()
	{
		_con.pop_front();
	}

	T& back()
	{
		return _con.back();
	}

	T& front()
	{
		return _con.front();
	}

	bool empty()const
	{
		return _con.empty();
	}

	size_t size()
	{
		return _con.size();
	}


private:
	Container _con;

};

template<class T, class Container>
inline void queue<T, Container>::push(const T& x)
{
	_con.push_back(x);
}

仿函数:

        仿函数(Functor),也称为函数对象,是通过重载operator()运算符使得类对象可以像函数一样被调用的技术。它常用于STL算法中,提供灵活且可定制的操作逻辑。

        仿函数设计出来是用来替代函数指针的。

template<class T>
struct greater 
{
    bool operator()(const T& l, const T& r) const 
    {
        return l > r;
    }
};


template<class T>
struct less 
{
    bool operator()(const T& l, const T& r) const 
    {
        return l < r;
    }
};

        

优先级队列(priority_queue):

        优先级队列(priority_queue)是C++标准库中的容器适配器,它基于堆数据结构实现,能够保证队列头部始终是最大(默认)或最小值的元素。

        底层的数据结构实际为堆(Heap)。

#include <queue>
priority_queue<int> pq; // 默认大顶堆
priority_queue<int, vector<int>, greater<int>> min_pq; // 小顶堆

PS:

  • Compare 进行比较的仿函数        less->大堆
  • Compare 进行比较的仿函数        greater->小堆
//compare进行比较的仿函数 less->大堆
template<class T, class Container = vector<T>, class Compare=std::less<T>>
class priority_queue
{
public:
	priority_queue()
	{}

	template<class InputIterator>
	priority_queue(InputIterator first, InputIterator last)
	{
		while (first!=last)
		{
			_con.push_back(*first);
			++first;
		}

		//建堆
		for (int i = (_con.size()-1-1)/2;i>=0;--i)
		{
			adjust_down(i);
		}
	}

	void adjust_up(size_t child)
	{
		Compare com;
		size_t parent = (child - 1) / 2;
		while (child > 0)
		{
			if (com(_con[parent] ,_con[child])) { //默认less 向上调整建大堆
				std::swap(_con[child] , _con[parent]);
				child = parent;
				parent = (child - 1) / 2;
			}
			else {
				break;
			}
		}
	}

	void push(const T& x)
	{
		_con.push_back(x);
		adjust_up(_con.size()-1);
	}

	void adjust_down(size_t parent)
	{
		Compare com;
		size_t child = parent * 2 + 1;
		while (child < _con.size()) {
			//选出左右孩子大的那一个 默认less 向下调整建小堆
			if (child + 1 < _con.size() && com(_con[child],_con[child+1])) {
				++child;
			}

			if (com(_con[parent], _con[child])) {
				std::swap(_con[child] , _con[parent]);
				parent = child; 
				child = parent * 2 + 1;
			}
			else {
				break;
			}

		}
	}

	void pop()
	{
		std::swap(_con[0], _con[_con.size() - 1]);
		_con.pop_back();

		adjust_down(0);
	}

	const T &top()const
	{
		return _con[0];
	}

private:
	Container _con;
};

        代码几乎都是前面写过的,关键是C++让其封装起来了。

代码还是有几个要注意的点:

        STL库里面priority用greater(大于) 比较建立小堆,less(小于)比较建立小堆。所以这里要跟标准库里面保持一致,所以要注意比较时,代码的顺序。

        而这里影响位置顺序的地方在向上调整和向下调整的函数上。

void adjust_up(size_t child)
{
	Compare com;
	size_t parent = (child - 1) / 2;
	while (child > 0)
	{
		if (com(_con[parent] ,_con[child])) { 
			std::swap(_con[child] , _con[parent]);
			child = parent;
			parent = (child - 1) / 2;
		}
		else {
			break;
		}
	}
}



void adjust_down(size_t parent)
{
	Compare com;
	size_t child = parent * 2 + 1;
	while (child < _con.size()) {
		if (child + 1 < _con.size() && com(_con[child],_con[child+1])) {
			++child;
		}

		if (com(_con[parent], _con[child])) {
			std::swap(_con[child] , _con[parent]);
			parent = child; 
			child = parent * 2 + 1;
		}
		else {
			break;
		}

	}
}

构建堆的复杂度差异:

  • 自底向上建堆:时间复杂度为 O(n),因为大多数节点位于低层。
  • 自顶向下建堆:时间复杂度为 O(n log n),因为每个元素插入时都可能需要 O(log n) 调整。

所以这里使用自底向上建堆。

_con[parent] > _con[child]
等价于 
_con[child] <  _con[parent] 

_con[parent] < _con[child]
等价于 
_con[child] >  _con[parent] 

        这里写法顺序的不同,会导致代码的意思不同。这里要跟库里面最好保持一直。库里面是greater(大于)建立小堆,所以这里 > 保持不变的情况下,_con[parent] 要放在左边, _con[child] 要放在右边 (自顶向下建堆

        根据代码的意思就可以知道,如果 _con[parent] > _con[child],则交换父子节点的数据,那么一直到根节点,数据变成了上面下,下面大的结构,就建成了小堆。同理 如果是  _con[child] > _con[parent],则变成了数据上面大,下面小的结构,会建成大堆。


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

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

    相关文章

    一周学会Pandas2 Python数据处理与分析-编写Pandas2 HelloWord项目

    锋哥原创的Pandas2 Python数据处理与分析 视频教程&#xff1a; 2025版 Pandas2 Python数据处理与分析 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili 我们首先准备一个excel文件&#xff0c;用来演示pandas操作数据集(数据的集合)。excel文件属于数据集的一种&#xf…

    【易订货-注册/登录安全分析报告】

    前言 由于网站注册入口容易被机器执行自动化程序攻击&#xff0c;存在如下风险&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露&#xff0c;不符合国家等级保护的要求。短信盗刷带来的拒绝服务风险 &#xff0c;造成用户无法登陆、注册&#xff0c;大量收到垃圾短信的…

    如何在Windows上找到Python安装路径?两种方法快速定位

    原文&#xff1a;如何在Windows上找到Python安装路径&#xff1f;两种方法快速定位 | w3cschool笔记 在 Windows 系统上找到 Python 的安装路径对于设置环境变量或排查问题非常重要。本文将介绍两种方法&#xff0c;帮助你找到 Python 的安装路径&#xff1a;一种是通过命令提…

    lvgl避坑记录

    一、log调试 #if LV_USE_LOG && LV_LOG_LEVEL > LV_LOG_LEVEL_INFOswitch(src_type) {case LV_IMG_SRC_FILE:LV_LOG_TRACE("lv_img_set_src: LV_IMG_SRC_FILE type found");break;case LV_IMG_SRC_VARIABLE:LV_LOG_TRACE("lv_img_set_src: LV_IMG_S…

    element-plus中,表单校验的使用

    目录 一.案例1&#xff1a;给下面的表单添加校验 1.目的要求 2.步骤 ①给需要校验的el-form-item项&#xff0c;添加prop属性 ②定义一个表单校验对象&#xff0c;里面存放了每一个prop的检验规则 ③给el-form组件&#xff0c;添加:rules属性 ④给el-form组件&#xff0…

    PyTorch复现线性模型

    【前言】 本专题为PyTorch专栏。从本专题开始&#xff0c;我将通过使用PyTorch编写基础神经网络&#xff0c;带领大家学习PyTorch。并顺便带领大家复习以下深度学习的知识。希望大家通过本专栏学习&#xff0c;更进一步了解人更智能这个领域。 材料来源&#xff1a;2.线性模型_…

    Kafka+Zookeeper从docker部署到spring boot使用完整教程

    文章目录 一、Kafka1.Kafka核心介绍&#xff1a;​核心架构​核心特性​典型应用 2.Kafka对 ZooKeeper 的依赖&#xff1a;3.去 ZooKeeper 的演进之路&#xff1a;注&#xff1a;&#xff08;本文采用ZooKeeper3.8 Kafka2.8.1&#xff09; 二、Zookeeper1.核心架构与特性2.典型…

    RK3568驱动 SPI主/从 配置

    一、SPI 控制器基础配置(先说主的配置&#xff0c;后面说从的配置) RK3568 集成高性能 SPI 控制器&#xff0c;支持主从双模式&#xff0c;最高传输速率 50MHz。设备树配置文件路径通常为K3568/rk356x_linux_release_v1.3.1_20221120/kernel/arch/arm64/boot/dts/rockchip。 …

    【全队项目】智能学术海报生成系统PosterGenius--风格个性化调整

    ​ &#x1f308; 个人主页&#xff1a;十二月的猫-CSDN博客 &#x1f525; 系列专栏&#x1f3c0;大模型实战训练营 ​&#x1f4aa;&#x1f3fb; 十二月的寒冬阻挡不了春天的脚步&#xff0c;十二点的黑夜遮蔽不住黎明的曙光 1.前言 PosterGenius致力于开发一套依托DeepSeek…

    【系统移植】(六)第三方驱动移植

    【系统移植】&#xff08;六&#xff09;第三方驱动移植 文章目录 【系统移植】&#xff08;六&#xff09;第三方驱动移植1.编译驱动进内核方法一&#xff1a;编译makefile方法二&#xff1a;编译kconfig方法三&#xff1a;编译成模块 2.字符设备框架 编译驱动进内核a. 选择驱…

    STM32实现一个简单电灯

    新建工程的步骤 建立工程文件夹&#xff0c;Keil中新建工程&#xff0c;选择型号工程文件夹里建立Start、Library、User等文件夹&#xff0c;复制固件库里面的文件到工程文件夹工程里对应建立Start、Library、User等同名称的分组&#xff0c;然后将文件夹内的文件添加到工程分组…

    【shiro】shiro反序列化漏洞综合利用工具v2.2(下载、安装、使用)

    1 工具下载 shiro反序列化漏洞综合利用工具v2.2下载&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1kvQEMrMP-PZ4K1eGwAP0_Q?pwdzbgp 提取码&#xff1a;zbgp其他工具下载&#xff1a; 除了该工具之外&#xff0c;github上还有其他大佬贡献的各种工具&#xff0c;有…

    vue进度条组件

    <div class"global-mask" v-if"isProgress"><div class"contentBox"><div class"progresstitie">数据加载中请稍后</div><el-progress class"progressStyle" :color"customColor" tex…

    CSRF跨站请求伪造——入门篇【DVWA靶场low级别writeup】

    CSRF跨站请求伪造——入门篇 0. 前言1. 什么是CSRF2. 一次完整的CSRF攻击 0. 前言 本文将带你实现一次完整的CSRF攻击&#xff0c;内容较为基础。需要你掌握的基础知识有&#xff1a; 了解cookie&#xff1b;已经安装了DVWA的靶场环境&#xff08;本地的或云的&#xff09;&am…

    Qt基础:主界面窗口类QMainWindow

    QMainWindow 1. QMainWindow1.1 菜单栏添加菜单项菜单项信号槽 1.2 工具栏添加工具按钮工具栏的属性设置 1.3 状态栏1.4 停靠窗口&#xff08;Dock widget&#xff09; 1. QMainWindow QMainWindow是标准基础窗口中结构最复杂的窗口, 其组成如下: 提供了菜单栏, 工具栏, 状态…

    32f4,usart2fifo,2025

    usart2fifo.h #ifndef __USART2FIFO_H #define __USART2FIFO_H#include "stdio.h" #include "stm32f4xx_conf.h" #include "sys.h" #include "fifo_usart2.h"//extern u8 RXD2_TimeOut;//超时检测//extern u8 Timer6_1ms_flag;exte…

    激光模拟单粒子效应试验如何验证CANFD芯片的辐照阈值?

    在现代航天电子系统中&#xff0c;CANFD&#xff08;Controller Area Network with Flexible Data-rate&#xff09;芯片作为关键的通信接口元件&#xff0c;其可靠性与抗辐射性能直接关系到整个系统的稳定运行。由于宇宙空间中存在的高能粒子辐射&#xff0c;芯片可能遭受单粒…

    从零构建大语言模型全栈开发指南:第五部分:行业应用与前沿探索-5.2.1模型偏见与安全对齐(Red Teaming实践)

    👉 点击关注不迷路 👉 点击关注不迷路 👉 点击关注不迷路 文章大纲 大语言模型全栈开发指南:伦理与未来趋势 - 第五部分:行业应用与前沿探索5.2.1 模型偏见与安全对齐(Red Teaming实践)一、模型偏见的来源与影响1. 偏见的定义与分类2. 偏见的实际影响案例二、安全对齐…

    Docker安装开源项目x-ui详细图文教程

    本章教程,主要介绍如何使用Docker部署开源项目x-ui 详细教程。 一、拉取镜像 docker pull enwaiax/x-ui:latest二、运行容器 mkdir x-ui && cd x-ui docker run -itd --network=host \-v $PWD<

    检索增强生成(RAG) 优化策略

    检索增强生成(RAG) 优化策略篇 一、RAG基础功能篇 1.1 RAG 工作流程 二、RAG 各模块有哪些优化策略&#xff1f;三、RAG 架构优化有哪些优化策略&#xff1f; 3.1 如何利用 知识图谱&#xff08;KG&#xff09;进行上下文增强&#xff1f; 3.1.1 典型RAG架构中&#xff0c;向…