容器适配器深度解析:从STL的stack、queue到优先队列的底层实现

容器适配器深度解析:从STL的stack、queue到优先队列的底层实现
在这里插入图片描述

文章目录

容器适配器深度解析:从STL的stack、queue到优先队列的底层实现

1. 栈的介绍和使用

1.1 栈的介绍

栈(stack)是一种后进先出(LIFO)的数据结构,它允许在一端进行插入和删除操作。在C++ STL中,stack是一个容器适配器,提供了一组特定的成员函数来访问其元素。

1.2 栈的使用

函数接口说明
stack()构造空的栈
empty()检测stack是否为空
size()返回stack中元素的个数
top()返回栈顶元素的引用
push()将元素val压入stack中
pop()将stack中尾部的元素弹出

最小栈实现

最小栈能够在O(1)时间内获取栈中的最小元素。

classMinStack{public:voidpush(int x){// 压栈时,先将元素保存到_elem _elem.push(x);// 如果x小于_min中栈顶的元素,将x再压入_min中if(_min.empty()|| x <= _min.top()) _min.push(x);}voidpop(){// 如果_min栈顶的元素等于出栈的元素,_min顶的元素要移除if(_min.top()== _elem.top()) _min.pop(); _elem.pop();}inttop(){return _elem.top();}intgetMin(){return _min.top();}private: std::stack<int> _elem;// 保存栈中的元素 std::stack<int> _min;// 保存栈的最小值};

栈的弹出压入序列

验证一个序列是否是栈的弹出序列。

在这里插入图片描述
classMinStack{public:MinStack(){}voidpush(int val){ st.push(val);if(minst.empty()||minst.top()>=val){ minst.push(val);}}voidpop(){if(st.top()==minst.top()){ minst.pop();} st.pop();}inttop(){return st.top();}intgetMin(){return minst.top();}private: stack<int> st; stack<int> minst;};

逆波兰表达式求值

classSolution{public:intevalRPN(vector<string>& tokens){ stack<int> s;for(size_t i =0; i < tokens.size();++i){ string& str = tokens[i];// str为数字if(!("+"== str ||"-"== str ||"*"== str ||"/"== str)){ s.push(atoi(str.c_str()));}else{// str为操作符int right = s.top(); s.pop();int left = s.top(); s.pop();switch(str[0]){case'+': s.push(left + right);break;case'-': s.push(left - right);break;case'*': s.push(left * right);break;case'/': s.push(left / right);break;}}}return s.top();}};

1.3 stack的模拟实现

以下是使用容器适配器模式实现的stack,支持自定义底层容器(默认使用deque):

#pragmaonce#include<deque>namespace bit {// container适配器实现stacktemplate<classT,classContainer= deque<T>>classstack{public:voidpush(const T& x){ _con.push_back(x);}voidpop(){ _con.pop_back();}const T&top()const{return _con.back();} size_t size()const{return _con.size();}boolempty(){return _con.empty();}private: Container _con;};}

2. 队列的介绍和使用

2.1 队列的介绍

队列是一种先进先出(FIFO)的数据结构,元素从队尾入队列,从队头出队列。在C++ STL中,queue是一个容器适配器。

queue的特点:

  1. 队列是一种容器适配器,专门用于在FIFO上下文(先进先出)中操作
  2. 元素从队尾入队列,从队头出队列
  3. 底层容器可以是deque或list,默认使用deque

2.2 queue的使用

函数声明接口说明
queue()构造空的队列
empty()检测队列是否为空
size()返回队列中有效元素的个数
front()返回队头元素的引用
back()返回队尾元素的引用
push()在队尾将元素val入队列
pop()将队头元素出队列

2.3 queue的模拟实现

使用容器适配器模式实现的queue,支持自定义底层容器:

#pragmaonce#include<deque>namespace bit {template<classT,classContainer= deque<T>>classqueue{public:voidpush(const T& x){ _con.push_back(x);}voidpop(){ _con.pop_front();}const T&front()const{return _con.front();}const T&back()const{return _con.back();} size_t size()const{return _con.size();}boolempty(){return _con.empty();}private: Container _con;};}

3. 优先队列的介绍和使用

3.1 priority_queue的介绍

优先队列是一种容器适配器,它的第一个元素总是它所包含的元素中最大的(默认大堆)。

priority_queue的特点:

  1. 第一个元素总是最大的(默认大堆)
  2. 类似于堆,可以随时插入元素,只能检索最大堆元素
  3. 默认使用vector作为底层容器
  4. 支持随机访问迭代器

3.2 priority_queue的使用

函数声明接口说明
priority_queue()构造一个空的优先级队列
priority_queue(first, last)用迭代器范围构造优先级队列
empty()检测优先级队列是否为空
top()返回优先级队列中最大(最小)元素
push(x)在优先级队列中插入元素x
pop()删除优先级队列中最大(最小)元素

使用示例:

#include<vector>#include<queue>#include<functional>// greater算法的头文件voidTestPriorityQueue(){// 默认情况下,创建的是大堆,其底层按照小于号比较 vector<int> v{3,2,7,6,0,4,1,9,8,5}; priority_queue<int> q1;for(auto& e : v) q1.push(e); cout << q1.top()<< endl;// 输出9// 创建小堆,将第三个模板参数换成greater比较方式 priority_queue<int, vector<int>, greater<int>>q2(v.begin(), v.end()); cout << q2.top()<< endl;// 输出0}

注意:

  1. 默认情况下,priority_queue是大堆
  2. 如果要创建小堆,需要指定第三个模板参数为greater<T>
  3. 如果存放自定义类型,需要在自定义类型中提供><的重载

3.3 priority_queue的模拟实现

以下是完整的优先队列模拟实现,包含大堆和小堆支持:

#pragmaonce#include<vector>namespace bit {// 仿函数类:Less(升序/大堆)template<classT>classLess{public:booloperator()(const T& x,const T& y){return x < y;}};// 仿函数类:Greater(降序/小堆)template<classT>classGreater{public:booloperator()(const T& x,const T& y){return x > y;}};// 优先队列实现// 模板参数:// T - 元素类型// Container - 底层容器,默认vector<T>// Compare - 比较器,默认Less<T>(大堆)template<classT,classContainer= vector<T>,classCompare= Less<T>>classpriority_queue{public:// 向上调整(插入时使用)voidAdjustUp(int child){ Compare com; size_t parent =(child -1)/2;while(child >0){// 使用仿函数进行比较if(com(_con[parent], _con[child])){swap(_con[child], _con[parent]); child = parent; parent =(child -1)/2;}else{break;}}}// 向下调整(删除时使用)voidAdjustDown(int parent){int child = parent *2+1; Compare com;while(child < _con.size()){// 找出较大(或较小)的孩子if(child +1< _con.size()&&com(_con[child], _con[child +1])){++child;}// 如果父节点小于(或大于)孩子节点,交换if(com(_con[parent], _con[child])){swap(_con[child], _con[parent]); parent = child; child = parent *2+1;}else{break;}}}// 插入元素voidpush(const T& x){ _con.push_back(x);AdjustUp(_con.size()-1);}// 删除堆顶元素voidpop(){swap(_con[0], _con[_con.size()-1]); _con.pop_back();AdjustDown(0);}// 获取堆顶元素const T&top(){return _con[0];}// 获取元素个数 size_t size()const{return _con.size();}// 判断是否为空boolempty()const{return _con.empty();}private: Container _con;};}

4. 容器适配器

4.1 什么是适配器

适配器是一种设计模式,将一个类的接口转换成客户希望的另外一个接口。

4.2 STL标准库中stack和queue的底层结构

stack和queue在STL中称为容器适配器,它们只是对其他容器的接口进行了包装。STL中stack和queue默认使用deque作为底层容器。

4.3 deque的简单介绍

4.3.1 deque的原理介绍

deque(双端队列)是一种双开口的"连续"空间的数据结构:

  • 可以在头尾两端进行插入和删除操作,时间复杂度为O(1)
  • 与vector比较,头插效率高,不需要搬移元素
  • 与list比较,空间利用率比较高

deque并不是真正连续的空间,而是由一段段连续的小空间拼接而成的,实际类似于一个动态的二维数组。

4.3.2 deque的缺陷
  • 不适合遍历,因为迭代器要频繁检测是否移动到小空间边界
  • 在实际中,需要线性结构时,大多数情况下优先考虑vector和list
  • deque的应用并不多,主要作为stack和queue的底层数据结构

4.4 为什么选择deque作为stack和queue的底层默认容器

  1. stack和queue不需要遍历(因此没有迭代器),只需要在固定的一端或两端操作
  2. 在stack中元素增长时,deque比vector的效率高(扩容时不需要搬移大量数据)
  3. queue中的元素增长时,deque不仅效率高,而且内存使用率高

4.5 容器适配器设计的关键点

从上面的模拟实现可以看出容器适配器的核心设计思想:

  1. 模板参数灵活性
    • stack和queue都支持自定义底层容器
    • priority_queue支持自定义比较器,实现大堆/小堆切换
  2. 接口统一性
    • 所有适配器都提供push、pop、top/front/back、size、empty等标准接口
    • 隐藏底层容器的具体实现细节
  3. 代码复用
    • 通过组合已有的容器实现新功能
    • 减少代码重复,提高开发效率

总结

栈、队列和优先队列是三种基础且重要的数据结构,在C++ STL中通过容器适配器的方式实现。理解它们的底层原理、使用场景和实现方式,对于提高编程能力和解决实际问题都有重要意义。

通过模拟实现这些数据结构,我们可以:

  1. 深入理解容器适配器设计模式
  2. 掌握仿函数在泛型编程中的应用
  3. 理解堆算法的实现原理
  4. 学会如何设计灵活的、可扩展的数据结构

在实际开发中,根据具体需求选择合适的数据结构:

  • 需要后进先出操作时选择栈
  • 需要先进先出操作时选择队列
  • 需要快速获取最大/最小值时选择优先队列

Read more

鸿蒙金融理财全栈项目——上线与运维、用户反馈、持续迭代优化

鸿蒙金融理财全栈项目——上线与运维、用户反馈、持续迭代优化

《鸿蒙APP开发从入门到精通》第25篇:鸿蒙金融理财全栈项目——上线与运维、用户反馈、持续迭代优化 🚀📱🔧 内容承接与核心价值 这是《鸿蒙APP开发从入门到精通》的第25篇——上线与运维、用户反馈、持续迭代优化篇,100%承接第24篇的生态合作、用户运营优化、数据产品变现优化架构,并基于金融场景的上线与运维、用户反馈、持续迭代优化要求,设计并实现鸿蒙金融理财全栈项目的上线与运维、用户反馈、持续迭代优化功能。 学习目标: * 掌握鸿蒙金融理财项目的上线与运维优化设计与实现; * 实现应用上线优化、应用运维优化、应用监控优化; * 理解用户反馈在金融场景的核心优化设计与实现; * 实现用户反馈收集优化、用户反馈分析优化、用户反馈处理优化; * 掌握持续迭代优化在金融场景的设计与实现; * 实现持续集成优化、持续部署优化、持续交付优化; * 优化金融理财项目的用户体验(上线与运维、用户反馈、持续迭代优化)。 学习重点: * 鸿蒙金融理财项目的上线与运维优化设计原则; * 用户反馈在金融场景的优化应用; * 持续迭代优化在金融场景的设计要点。 一、

By Ne0inhk

DeepSeek-R1-Distill-Llama-8B实战:快速搭建智能问答系统

DeepSeek-R1-Distill-Llama-8B实战:快速搭建智能问答系统 1. 模型介绍与优势 DeepSeek-R1-Distill-Llama-8B是一个经过知识蒸馏优化的推理模型,它在保持较小参数规模的同时,具备了强大的语言理解和生成能力。这个8B参数的模型在性能和计算资源消耗之间找到了很好的平衡点,特别适合需要快速响应和高效推理的智能问答场景。 这个模型基于DeepSeek-R1的先进技术,通过蒸馏过程将大模型的知识压缩到更小的架构中。这意味着你可以在普通的硬件环境下运行它,而不需要昂贵的专业设备。对于想要搭建智能问答系统的开发者来说,这无疑是个好消息——你既不需要担心模型太大跑不动,也不用担心效果不够好。 在实际测试中,DeepSeek-R1-Distill-Llama-8B在多个基准测试中都表现不错。特别是在数学推理、代码生成和一般问答任务上,它的表现可以媲美一些更大的模型。这使它成为搭建智能问答系统的理想选择,无论是用于教育辅导、技术支持还是日常问答,都能提供可靠的服务。 2. 环境准备与快速部署 2.1 系统要求与依赖安装 在开始之前,确保你

By Ne0inhk
Matlab Copilot_AI工具箱: 对接DeepSeek/Kimi/GPT/千问/文心一言等多款AI大模型,一站式提升编程效率

Matlab Copilot_AI工具箱: 对接DeepSeek/Kimi/GPT/千问/文心一言等多款AI大模型,一站式提升编程效率

🔥 为什么需要这款工具? * Matlab 2025虽自带Copilot功能,但受地区、许可证的限制,多数用户无法使用; * 在Matlab和ChatGPT、DeepSeek等AI模型之间来回切换操作繁琐,无法实现“所见即所得”的编程体验,且代码报错后的调试繁琐。 这款Matlab Copilot_AI工具箱作为Matlab与多款AI模型的对接载体,支持DeepSeek V3.2(基础/思考版)、Kimi K2、百度文心一言、阿里云通义千问、ChatGPT(百度千帆版)等模型,还支持4种自定义模型配置(可对接百度千帆平台近百种大模型); 工具直接在Matlab内(不限于2025a)运行,无需切换其他软件,支持“一键生成、运行、调试、修复bug、导出”全流程编程辅助,使用成本可控(单模型月均几元即可满足基础使用),且工具箱一次授权终身免费更新。 多款AI模型可选择,还支持四种自定义模型组合。 更新记录 1. 20260123更新至v4.0,更新:

By Ne0inhk
【保姆级教程】llama.cpp大模型部署全攻略:CPU/GPU全兼容,小白也能轻松上手!

【保姆级教程】llama.cpp大模型部署全攻略:CPU/GPU全兼容,小白也能轻松上手!

一、简介 * • llama.cpp 是一个在 C/C++ 中实现大型语言模型(LLM)推理的工具 * • 支持跨平台部署,也支持使用 Docker 快速启动 * • 可以运行多种量化模型,对电脑要求不高,CPU/GPU设备均可流畅运行 * • 开源地址参考:https://github.com/ggml-org/llama.cpp • 核心工作流程参考: 二、安装与下载模型(Docker方式) 1. 搜索可用模型 • 这里以 qwen3-vl 模型为例,提供了多种量化版本,每种版本的大小不一样,根据自己的电脑性能做选择,如选择(模型+量化标签):Qwen/Qwen3-VL-8B-Instruct-GGUF:Q8_0 • 可以在huggingface官网中搜索可用的量化模型:https://huggingface.co/models?search=

By Ne0inhk