news 2026/5/16 6:49:03

C++-stack和queue

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
C++-stack和queue

一、stack的介绍、使用和模拟实现

1.1 stack的介绍

1.stack是一种容器适配器(container adaptor),专门设计用于后进先出(LIFO)的环境,即元素只能从一端进行插入和删除

2.stack是以容器适配器的方式进行实现的,是使用特定的容器类作为底层容器进行封装实现的类,容器适配器会提供特殊的成员函数来实现stack访问元素的功能。任何标准容器只要拥有以下接口便可作为stack的底层容器。

empty push_back pop_back size back

vector、list、deque都可以作为stack的底层容器。

3.

模板参数介绍:

T:元素类型模板 Container:底层容器模板

1.2 stack的使用

1.stack的核心接口有:

stack()、push、pop、top、empty、size
接口接口说明
stack()stack的构造函数
push将元素val压栈
pop弹出栈顶元素
top获取栈顶元素
empty判断栈是否为空
size获取栈内有效元素的个数
void test_stack() { //构造 stack<int> st; //插入 st.push(1); st.push(2); st.push(3); st.push(2); //获取数据个数 cout << st.size() << endl; //4 //弹出栈顶元素 st.pop(); st.pop(); //获取栈顶元素 cout << st.top() << endl; //2 st.pop(); st.pop(); //判空 cout << st.empty(); //1 }

1.3 stack做为容器适配器的模拟实现

1.模拟实现分为以下几个部分:

#stack.h #include<vector> namespace xxx { template<class T,class Container = vector<T>> class stack { public: void push(const T& val) { _con.push_back(val); } void pop() { _con.pop_back(); } const T& top() { return _con.back(); } bool empty() { return _con.empty(); } size_t size() { return _con.size(); } private: //成员变量是底层容器实例化的对象 Container _con; }; }

2.模拟实现的stack的使用

#include<iostream> #include<deque> using namespace std; #include"stack.h" void test_stack() { //使用默认的底层容器 xxx::stack<int> st1; //使用库里面的标准容器作为底层容器 xxx::stack<int, deque<int>> st2; st1.push(1); st1.push(2); st2.push(1); st2.push(2); st1.pop(); st2.pop(); cout << st1.size() << endl; //1 cout << st1.empty() << endl; //0 cout << st1.top() << endl; //1 cout << st2.size() << endl; //1 cout << st2.empty() << endl; //0 cout << st2.top() << endl; //1 }

二、queue的介绍、使用和模拟实现

2.1 queue的介绍

1.queue也是一种容器适配器(container adaptor),专门设计拥有先进先出(FIFO)的环境,即元素从一端插入队列从队列的另一端进行提取。

2.队列作为容器适配器实现的类,即将特定的容器类进行封装作为其底层容器实现的类,容器适配器会提供特殊的成员函数类实现queue访问元素的功能。任何标准容器只要提供以下接口便可作为queue的底层容器。

empty size front back pop_front push_back

deque、list都可以作为queue的底层容器。

3.

模板参数介绍:

T:元素类型模板 Container:底层容器模板

2.2 queue的使用

1.queue的核心接口有:

queue()、push、pop、front、back、empty、size
接口接口介绍
queue()queue的构造函数
push()在队尾插入一个元素
pop()弹出队头的元素
front()获取队头的元素
back()获取队尾的元素
empty()判断队列是否为空
size()获取队列内有效数据个数
void test_queue() { //使用构造函数创建一个队列 queue<int> q; //在队尾插入元素 q.push(1); q.push(2); q.push(3); q.push(4); q.push(5); //删除队头的元素 q.pop(); q.pop(); //获取队头和队尾的元素 cout << q.front() << endl; //3 cout << q.back() << endl; //5 //获取队列内有效元素个数 cout << q.size() << endl; //3 //判断队列是否为空 cout << q.empty() << endl; //0 }

2.3 队列作为容器适配器的模拟实现

队列的模拟实现部分和栈的模拟实现部分差不多。

#queue.h #include<list> namespace xxx { template<class T,class Container = list<T>> class queue { public: void push(const T& val) { _con.push_back(val); } void pop() { _con.pop_front(val); } const T& front() { return _con.front(); } const T& back() { return _con.back(); } bool empty() { return _con.empty(); } size_t size() { return _con.size(); } private: Container _con; }; }

模拟实现的队列使用也和栈差不多:

#include<iostream> #include<deque> using namespace std; #include"queue.h" void test_queue() { xxx::queue<int> q1; xxx::queue<int, deque<int>> q2; //... }

三、priority_queue的介绍、使用和模拟实现

3.1 priority_queue的介绍

1.优先级队列(priority_queue)也是一个容器适配器(container adaptor)默认的底层实现是一个大堆,从堆底插入元素,在进行向上调整后需要依旧保持堆的特性,删除元素时会删除堆顶的元素,删除步骤是将堆顶和堆底的元素进行交换,然后删除堆底的元素,对堆顶的元素进行向下调整,需要依旧保持堆的特性。

2.优先级队列是被实现为容器适配器的类,同样也是使用特定的容器进行封装作为其底层容器的类,优先级队列相较于其他的容器适配器而言,需要底层容器拥有随机访问迭代器的功能。在这个前提下能提供以下接口的标准容器就可以作为优先级队列的底层容器。

empty size front push_back pop_back

标准容器vector、deque可以作为优先级队列(priority_queue)的底层容器。

3.模板参数介绍:

template<class T,class Container = vector<T>,class Compare = less<typename Container::value_type>> T:元素模板 Container:底层容器模板 Compare:仿函数模板

3.2 priority_queue的使用(包括仿函数的设置控制大小堆)

1.priority_queue的核心接口:

priority_queue()、priority_queue(first,last)、push、pop、top、size、empty
接口接口介绍
priority_queue()优先级队列的默认构造函数
priority_queue(first,last)使用一段迭代器区间构造优先级队列
push插入一个元素
pop删除优先级队列顶部元素
top获取优先级队列顶部的元素
size获取有效元素的个数
empty判断优先级队列是否为空
void priority_queue_test() { //使用默认构造 priority_queue<int> pq1; //使用迭代器区间构造 vector<int> v = { 10,5,6,7,4,3,1,2 }; priority_queue<int> pq2(v.begin(), v.end()); //插入一个8 pq2.push(8); //删除顶部元素 pq2.pop(); //获取顶部元素 cout << pq2.top() << endl; //8 //获取有效数据个数 cout << pq2.size() << endl; //8 //判空 cout << pq2.empty() << endl; //0 }

2.优先级队列的模板参数列表里面有一个仿函数模板,这个仿函数模板是用于改变优先级队列的底层是选择大堆控制还是小堆控制。库里面默认优先级队列的底层是大堆。

大堆小堆的切换方式:使用less仿函数时为大堆,使用greater仿函数时为小堆

//设置底层为大堆 priority_queue<int> pq1; priority_queue<int, vector<int>, less<int>> pq2; //设置底层为小堆 priority_queue<int, vector<int>, greater<int>> pq3;

3.3 priority_queue的模拟实现

优先级队列的模拟实现和stack、queue的模拟实现多了一个仿函数成员变量。

还有一点迭代器区间初始化优先级列队时需要一个额外的迭代器模板参数

#include<vector> namespace xxx { //template<class T, class Container = vector<T>> //添加仿函数模板 template<class T, class Container = vector<T>,class Compare=Less<T>> class priority_queue { public: template<class InputIterator> priority_queue(InputIterator first, InputIterator last) :_con(first,last) { //向下调整建堆 for (int end = ((_con.size() - 1) - 1) / 2; end >= 0; end--) { adjust_down(end); } } void swap(T& x, T& y) { T tmp = x; x = y; y = tmp; } void adjust_up(int child) { int parent = (child - 1) / 2; while (child > 0) { //if (_con[child] > _con[parent]) if(_com(_con[parent],_con[child])) { swap(_con[child], _con[parent]); child = parent; parent = (child - 1) / 2; } else { break; } } } void adjust_down(int parent) { int child = parent * 2 + 1; while (child < size()) { //if ((child + 1) < size() && _con[child + 1] > _con[child]) if ((child + 1) < size() && _com(_con[child],_con[child+1])) { child += 1; } //if (_con[child] > _con[parent]) if (_com(_con[parent],_con[child])) { swap(_con[child], _con[parent]); parent = child; child = parent * 2 + 1; } else { break; } } } void push(const T& x) { _con.push_back(x); adjust_up(size()-1); } void pop() { swap(_con[0], _con[size() - 1]); _con.pop_back(); adjust_down(0); } T& top() { return _con[0]; } size_t size() { return _con.size(); } bool empty() { return _con.empty(); } private: Container _con; //仿函数成员变量 Compare _com; }; }

模拟实现的priority_queue的使用:

#include<iostream> using namespace std; #include"priority_queue.h" //拥有控制模拟实现的优先级队列的仿函数 template<class T> class Less { public: bool operator()(const T& x, const T& y) { return x < y; } }; template<class T> class Greater { public: bool operator()(const T& x, const T& y) { return x > y; } }; void priority_queue_test() { vector<int> v= { 10,5,6,7,4,3,1,2 }; xxx::priority_queue<int> pq(v.begin(), v.end()); while (!pq.empty()) { cout << pq.top() << " "; //10 7 6 5 4 3 2 1 pq.pop(); } cout << endl; xxx::priority_queue<int,vector<int>,Greater<int>> pq1(v.begin(), v.end()); while (!pq1.empty()) { cout << pq1.top() << " "; //1 2 3 4 5 6 7 10 pq1.pop(); } cout << endl; }

四、容器适配器(Container Adaptor)

4.1 适配器的概念

适配器是一种设计模式,这种模式是将一个类的接口转换成用户希望的另一种接口,例如220V的电压通过设计成不同类型的插座可以满足不同类型的插头的需求。

容器适配器的意思就是:可以通过模板参数控制底层容器。

4.2 STL标准库里面的stack、queue、priority_queue的默认底层容器

stack和queue的默认底层容器使用的是deque,priority_queue的默认底层容器使用的是vector。

4.3 deque的简单介绍

1.双端队列(deque):是一种双开口的连续空间的数据结构,双开口是指可以在头尾和尾部插入和删除数据,且时间复杂度为O(1),与vector相比,可以在头部进行插入删除数据,与list相比,可以通过operator[]更快的访问数据

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

3.双端队列底层是一段假象的连续空间,实际上是分段连续的,为了维护其整体的连续性以及随机访问的功能,deque的迭代器设计也比较复杂。

4.deque的优点与缺陷

4.1 deque的头部和尾部的插入删除数据很方便,且扩容代价也比较低。

4.2 如果需要deque在中间进行插入或删除数据,有两种方案:

1.对单个buff数组进行扩容,但会导致每个buff内部的数据个数不同 2.每个buff的数据个数保持不变,对整体的数据进行挪动,然后再插入数据

中间的插入数组主要会影响operator[]的效率。

operator[]的实现:

//假设查找operator[i]位置上的数据 1.i-=第一个buff的数据个数,因为第一个buff在经过头插后数据可能不满。 2.x=i/(每个buff内数据个数),x是i处于第几个buff的位置。 3.y=i%10,y是i在第x+1个buf上的具体位置。

因此deque在中间的插入和删除效率是很低的。

4.3 deque不适合遍历,在拥有大量数据的情况下,buff的迭代器需要去频繁检测是否移动到了某段buff的边界,会导致效率很低。

4.4 STL标准库里面选择deque作为stack和queue的底层容器的原因

1.stack和queue不需要遍历,只需要在一端或两端进行插入删除数据。

2.stack的元素增长时,deque比vector的扩容效率高,且deque不需要挪动数据;queue的元素增长时deque不仅效率高而且在内存使用率方面要比list更好。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/16 6:48:04

用AI工具做技术课程:一个人完成录课、剪辑、上架全流程

软件测试从业者的知识变现新路径作为一名软件测试工程师&#xff0c;你手里握着大量值钱的东西——接口自动化怎么搭、性能瓶颈怎么定位、测试用例怎么设计才不漏测。这些东西在你的团队里可能是常识&#xff0c;但放到整个行业&#xff0c;就是别人愿意付费学习的硬通货。但一…

作者头像 李华
网站建设 2026/5/16 6:48:03

微信网页版访问终极指南:wechat-need-web插件完整教程

微信网页版访问终极指南&#xff1a;wechat-need-web插件完整教程 【免费下载链接】wechat-need-web 让微信网页版可用 / Allow the use of WeChat via webpage access 项目地址: https://gitcode.com/gh_mirrors/we/wechat-need-web 还在为无法在浏览器中使用微信网页版…

作者头像 李华
网站建设 2026/5/16 6:47:13

AI规则引擎:从自然语言到智能决策的技术实践

1. 项目概述&#xff1a;当AI开始制定规则 最近在GitHub上看到一个挺有意思的项目&#xff0c;叫 roderik/ai-rules 。光看这个名字&#xff0c;你可能以为又是一个关于如何用AI生成代码规则或者自动化测试的工具。但点进去仔细研究后&#xff0c;我发现它的内核要深刻得多。…

作者头像 李华
网站建设 2026/5/16 6:43:28

Exynos 5410处理器:big.LITTLE架构与28nm工艺的移动计算革命

1. Exynos 5410处理器&#xff1a;移动计算的新标杆2013年&#xff0c;当智能手机和平板电脑的性能需求开始爆发式增长时&#xff0c;三星推出了Exynos 5410处理器&#xff0c;这款SoC在当时堪称移动计算领域的一次革命。作为全球首款采用big.LITTLE架构的八核处理器&#xff0…

作者头像 李华
网站建设 2026/5/16 6:42:04

DsHidMini终极指南:让PS3手柄在Windows上焕发第二春的免费方案

DsHidMini终极指南&#xff1a;让PS3手柄在Windows上焕发第二春的免费方案 【免费下载链接】DsHidMini Virtual HID Mini-user-mode-driver for Sony DualShock 3 Controllers 项目地址: https://gitcode.com/gh_mirrors/ds/DsHidMini 还在为闲置的索尼DualShock 3手柄寻…

作者头像 李华
网站建设 2026/5/16 6:36:17

陕西高危工业场景防爆监控技术方案与选型标准

一、引言陕西作为我国西部工业核心区域&#xff0c;聚集了大量矿山、石油化工、海洋工程等高危行业企业。此类场景普遍存在易燃易爆、高粉尘、强腐蚀、潮湿盐雾等极端环境特征&#xff0c;普通监控设备因缺乏防爆设计与环境防护能力&#xff0c;极易出现故障甚至引发安全事故。…

作者头像 李华