【C++】stack和queue

stack和queue

  • 1. stack
    • 1.1 简单了解stack
    • 1.2 stack的常见接口
    • 1.3 练习
    • 1.4 模拟实现stack
  • 2. queue
    • 2.1 简单了解queue
    • 2.2 queue的常见接口
    • 2.3 练习
    • 2.4 模拟实现queue
  • 3. deque(了解)
  • 4. priority_queue
    • 4.1 优先级队列的介绍
    • 4.2 priority_queue的常见接口
    • 4.3 练习
    • 4.4 模拟实现priority_queue


1. stack

1.1 简单了解stack

在这里插入图片描述

  1. stack是一种容器适配器,是通过对特殊类或者容器的封装,获得想要的容器。stack的底层是类或者容器。
  2. stack支持后进先出,只能在一端进行操作。
  3. stack的底层容器应该支持stack的基本操作,例如push_back()尾插,pop_back()尾删,empty()判断栈空等操作。
  4. stack默认使用deque作为底层容器(后面讲),而vector、list也满足条件。

1.2 stack的常见接口

void test()
{//构造stack<int> st;//push尾插st.push(1);st.push(2);st.push(3);st.push(4);//empty判断为空while (!st.empty()){//top输出栈顶元素cout << st.top() << " ";//pop尾删st.pop();}cout << endl;
}
//结果
//4 3 2 1

1.3 练习

  1. 最小栈(LeetCode155)
//思路:利用两个栈,_st将元素正常入栈,_minSt比较入栈元素和栈顶元素,
//小于或者等于栈顶元素就入栈;出栈时,如果_st的栈顶元素和_minSt的栈顶元素相同就一同出栈
class MinStack {
public:MinStack() {}void push(int val) {_st.push(val);if(_minSt.empty()||val<=_minSt.top()){_minSt.push(val);}}void pop() {if(_st.top()==_minSt.top()){_st.pop();_minSt.pop();}else{_st.pop();}}int top() {return _st.top();}int getMin() {return _minSt.top();}
private:stack<int> _st;//用来存储正常元素stack<int> _minSt; //用来存储最小元素
};
  1. 栈的压入和弹出序列(牛客)
 //根据入栈序列判断出栈序列是否正确bool IsPopOrder(vector<int>& pushV, vector<int>& popV){// write code herestack<int> st;//用来入栈和出栈int ipushV = 0;//用来记录入栈序列的下标int ipopV = 0;//用来记录出栈序列的下标//当入栈顶序列的元素都入栈顶后,停止循环while(ipushV<pushV.size()){//直接入栈st.push(pushV[ipushV++]);//判断栈顶元素是否和出栈序列相同//不同就继续入栈,相同就出栈,依次与出栈序列比较if(st.top()!=popV[ipopV]){continue;}else {while(!st.empty()&&st.top()==popV[ipopV]){st.pop();++ipopV;}}}//如果为空,说明出栈序列为真return st.empty();}
  1. 逆波兰表达式求值(LeetCode150)
class Solution {
public://(1)逆波兰表达式是后缀表达式。//(2)用后缀表达式计算出表达式的值,需要用到栈。//(3)首先将操作数入栈,然后遇到操作符就取出栈顶两个元素进行运算,同时将计算结果入栈。int evalRPN(vector<string>& tokens) {stack<int> st;for(size_t i = 0;i<tokens.size();i++){if(tokens[i]=="+"||tokens[i]=="-"||tokens[i]=="*"||tokens[i]=="/"){//注意:先取出的是右操作数int right = st.top();st.pop();int left = st.top();st.pop();//tokens每个元素都是string类型switch(tokens[i][0]){case '+':st.push(left+right);break;case '-':st.push(left-right);break;case '*':st.push(left*right);break;case '/':st.push(left/right);break;}}else{st.push(stoi(tokens[i]));}}return st.top();}
};

1.4 模拟实现stack

namespace zn
{//stack默认适配的容器是deque,deque后面会讲到template<class T,class Container = deque<T>>class stack{Container _con;public://不用写构造,_con会自动调用其构造void push(const T& val){_con.push_back(val);}void pop(){_con.pop_back();}bool empty(){return _con.empty();}T& top(){return _con.back();}size_t size(){return _con.size();}};void test_stack(){stack<int> st;st.push(1);st.push(2);st.push(3);st.push(4);cout << st.size() << endl;while (!st.empty()){cout << st.top() << " ";st.pop();}cout << endl;//底层容器也可以用vector和list//stack<int, vector<int>>  st1;stack<int, list<int>> st2;st2.push(1);st2.push(2);st2.push(3);st2.push(4);cout << st2.size() << endl;while (!st2.empty()){cout << st2.top() << " ";st2.pop();}}
}

2. queue

2.1 简单了解queue

在这里插入图片描述

  1. queue也是一种容器适配器。底层是特殊类或者其他容器。
  2. queue支持先进先出,只能在一端插入,在另一端删除。
  3. queue的底层容器应该支持queue的基本操作,例如push_back尾插,pop_front头删,front输出队头元素,back输出队尾元素等操作。
  4. 如果没有为queue指定容器,则默认使用deque。

2.2 queue的常见接口

void test1()
{queue<int> q;q.push(1);q.push(2);q.push(3);q.push(4);while (!q.empty()){cout << q.front() << " ";q.pop();}cout <<  endl;
}

2.3 练习

  1. 二叉树的层序遍历(LeetCode102)
class Solution {
public://思路:从上到下,将一层节点放到一个队列中,用vector<int>记录一层节点的值,将这层节点出队时同时将下一层节点入队(其中为了区分不同层次,利用levelsize记录每层节点的个数),再将vector<int>放到vector<vector<int>>中vector<vector<int>> levelOrder(TreeNode* root) {vector<vector<int>> vv;int levelsize = 0;//记录当前这层的节点个数queue<TreeNode*> q;if(root!=nullptr){q.push(root);levelsize = 1;}while(!q.empty()){vector<int> v;for(size_t i = 0;i<levelsize;i++){TreeNode* tmp = q.front();q.pop();v.push_back(tmp->val);if(tmp->left){q.push(tmp->left);}if(tmp->right){q.push(tmp->right);}}vv.push_back(v);levelsize = q.size();}return vv;}
};
  1. 二叉树的层序遍历Ⅱ(LeetCode107)
class Solution {
public://只需在上一题的基础上,加上逆置即可。vector<vector<int>> levelOrderBottom(TreeNode* root) {queue<TreeNode*> q;vector<vector<int>> vv;int levelSize;if(root){q.push(root);levelSize = 1;}while(!q.empty()){vector<int> v;for(int i = 0;i<levelSize;i++){TreeNode* front = q.front();q.pop();v.push_back(front->val);if(front->left){q.push(front->left);}if(front->right){q.push(front->right);}}levelSize = q.size();vv.push_back(v);}reverse(vv.begin(),vv.end());return vv;}
};

2.4 模拟实现queue

namespace zn
{template<class T,class Container = deque<T>>class queue{Container _con;public:void push(const T& val){_con.push_back(val);}void pop(){_con.pop_front();}bool empty(){return _con.empty();}size_t size(){return _con.size();}T& front(){return _con.front();}T& back(){return _con.back();}};void test_queue(){queue<int> qt;qt.push(1);qt.push(2);qt.push(3);qt.push(4);cout << qt.front() << " " << qt.back() << endl;while (!qt.empty()){cout << qt.front() << " ";qt.pop();}cout << endl;//queue的底层容器可以是list,但不适合用vector适配,//因为vector没有提供头删的接口。如果要强制适配,可以用vector.erase(begin())queue<int, list<int>> qt1;qt1.push(1);qt1.push(2);qt1.push(3);qt1.push(4);cout << qt1.front() << " " << qt1.back() << endl;while (!qt1.empty()){cout << qt1.front() << " ";qt1.pop();}cout << endl;}
}

3. deque(了解)

deque为什么可以作为stack和queue的底层容器?它到底是什么?它有什么优点和缺点?不急,先了解下deque。
在这里插入图片描述

  1. deque是双端队列,是可以两端进行插入和删除的容器,具有一段“连续”的内存空间。

  2. 因此deque的头插头删和尾插尾删效率非常高,时间复杂度是O(1),效率比vector高;因为是“连续”的空间,空间利用率比list高。

  3. 此处的“连续”并不是指物理上的连续,deque的内存空间是由一段一段的连续空间组成的,类似于二维数组,只不过这个二位数组可以扩容。
    在这里插入图片描述

  4. 既然deque这么厉害,为什么只在stack和queue的底层才认识到它?deque看来是弥补了vector和list的缺点。但是没有取得其精华。相比于vector,deque极大缓解了扩容问题、头插头删问题,但下标访问不够极致,得计算在哪一段空间,在那段空间的第几个;相比于list,deque能够支持下标访问,因为空间是一段一段的,CPU高速缓存效率不错,头插头删不错,但中间插入和删除效率低。

  5. 综上,什么情况下使用deque最好?需要高频的头插头删和尾插尾删,不适合中间插入和删除以及高频的随机访问。用来适配stack和queue刚刚好(取其精华,去其糟粕)。


4. priority_queue

4.1 优先级队列的介绍

在这里插入图片描述

  1. priority_queue是容器适配器,底层是二叉树的堆,默认是大堆。
  2. priority_queue可以支持随机访问,并支持堆的基本操作,例如push_back尾插入,front输出堆顶元素,empty判断堆空,size输出元素数量。
  3. priority_queue的底层容器默认是vector,也可以用deque作为底层容器。

4.2 priority_queue的常见接口

void test_priority_queue()
{priority_queue<int> pq;//尾插pq.push(1);pq.push(3);pq.push(4);pq.push(2);//判断是否为空while (!pq.empty()){//输出堆顶元素cout << pq.top() << " ";//尾删(实际上是删除堆顶元素)pq.pop();}cout << endl;
}

4.3 练习

数组中第K个最大元素(LeetCode215)

class Solution {
public:int findKthLargest(vector<int>& nums, int k) {//法1:建立大堆,pop(k-1)次,此时堆顶元素就是第k个最大元素// priority_queue<int> pq(nums.begin(),nums.end());// while(--k)// {//     pq.pop();// }// return pq.top();//法2:建立有k个元素的小堆,如果比堆顶元素大就入堆,最终堆顶元素就是第k个最大元素priority_queue<int,vector<int>,greater<int>> pq;size_t i = 0;for(i = 0;i<k;i++){pq.push(nums[i]);}for(;i<nums.size();i++){if(nums[i]>pq.top()){pq.pop();pq.push(nums[i]);}}return pq.top();}
};

4.4 模拟实现priority_queue

namespace zn
{//仿函数本质上是一个类对象,可以像函数一样使用,所以叫仿函数//模拟实现仿函数template<class T>class less{public:bool operator()(const T& left, const T& right){return left < right;}};template<class T>class greater{public:bool operator()(const T& left, const T& right){return left > right;}};//有仿函数,只需要传递不同的仿造函数,不用修改代码,可以实现大堆和小堆template<class T,class Container = vector<T>,class Compare = less<T>>class priority_queue{Container _con;void AdjustDown(int parent){Compare com;int child = 2 * parent + 1;while (child < size()){if (child + 1 < size() && com(_con[child], _con[child + 1])){++child;}if (com(_con[parent], _con[child])){swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}void swap(T& left, T& right){T tmp = left;left = right;right = tmp;}void AdjustUp(int child){Compare com;int parent = (child - 1) / 2;while (child > 0){if (com(_con[parent], _con[child])){swap(_con[parent], _con[child]);child = parent;parent = (child - 1) / 2;}else{break;}}}public:priority_queue(){}template<class InputIterator>priority_queue(InputIterator begin,InputIterator end){while (begin != end){_con.push_back(*begin);++begin;}for (int i = (_con.size() - 1 - 1) / 2; i >= 0; i--){AdjustDown(i);}}void push(const T& val){_con.push_back(val);AdjustUp(size()-1);}void pop(){swap(_con[0], _con[size() - 1]);_con.pop_back();AdjustDown(0);}int size(){return _con.size();}bool empty(){return _con.empty();}T& top(){return _con.front();}};void test(){//建立大堆priority_queue<int> pq;pq.push(1);pq.push(5);pq.push(2);pq.push(4);pq.push(3);while (!pq.empty()){cout << pq.top() << " ";pq.pop();}cout << endl;//建立小堆priority_queue<int,vector<int>,greater<int>> p;p.push(1);p.push(5);p.push(2);p.push(4);p.push(3);while (!p.empty()){cout << p.top() << " ";p.pop();}cout << endl;}
}

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

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

相关文章

【80天学习完《深入理解计算机系统》】第十天 3.3 条件码寄存器【CF ZF SF OF】【set】

专注 效率 记忆 预习 笔记 复习 做题 欢迎观看我的博客&#xff0c;如有问题交流&#xff0c;欢迎评论区留言&#xff0c;一定尽快回复&#xff01;&#xff08;大家可以去看我的专栏&#xff0c;是所有文章的目录&#xff09;   文章字体风格&#xff1a; 红色文字表示&#…

Python Scrapy网络爬虫框架从入门到实战

Python Scrapy是一个强大的网络爬虫框架&#xff0c;它提供了丰富的功能和灵活的扩展性&#xff0c;使得爬取网页数据变得简单高效。本文将介绍Scrapy框架的基本概念、用法和实际案例&#xff0c;帮助你快速上手和应用Scrapy进行数据抓取。 Scrapy是一个基于Python的开源网络爬…

如何进行微服务的集成测试

集成测试的概念 说到集成测试&#xff0c;相信每个测试工程师并不陌生&#xff0c;它不是一个崭新的概念&#xff0c;通过维基百科定义可以知道它在传统软件测试中的含义。 Integration testing (sometimes called integration and testing, abbreviated I&T) is the pha…

Git 版本控制系统

git相关代码 0、清屏幕&#xff1a;clear 1、查看版本号 git -v2、暂存、更改、提交 3、当前项目下暂存区中有哪些文件 git ls-files4、查看文件状态 git status -s5、暂时存储&#xff0c;可以临时恢复代码内容 git restore 目标文件 //&#xff08;注意&#xff1a;完全…

自动控制原理笔记-采样控制系统

目录 采样控制系统的基本概念&#xff1a; 采样过程及采样定理&#xff1a; 一、采样过程 二、采样定理&#xff08;香农采样定理、奈奎斯特采样定律&#xff09; 三、信号复现 四、零阶保持器 z变换与z反变换&#xff1a; z变换的定义 z变换基本定理 z反变换 采样系…

谷歌面试-扔鸡蛋

今天想跟大家分享一个有意思的面试题&#xff0c;这让我再一次感叹思维的奇妙&#xff0c;接下来我们一起看看吧~ 首先来看看题目&#xff1a; 你有2颗鸡蛋&#xff0c;需要以最少的尝试次数来判断在100层的高楼上&#xff0c;哪一层楼是鸡蛋的安全层。 换句话说&#xff0c…

EureKa快速入门

EureKa快速入门 远程调用的问题 多个服务有多个端口&#xff0c;这样的话服务有多个&#xff0c;硬编码不太适合 eureKa的作用 将service的所有服务的端口全部记录下来 想要的话 直接从注册中心查询对于所有服务 每隔一段时间需要想eureKa发送请求 保证服务还存活 动手实践 …

【C语言基础】源文件与头文件详解

&#x1f4e2;&#xff1a;如果你也对机器人、人工智能感兴趣&#xff0c;看来我们志同道合✨ &#x1f4e2;&#xff1a;不妨浏览一下我的博客主页【https://blog.csdn.net/weixin_51244852】 &#x1f4e2;&#xff1a;文章若有幸对你有帮助&#xff0c;可点赞 &#x1f44d;…

五、多表查询-3.3连接查询-自连接

一、语法 二、演示-自连接&#xff08;内连接&#xff09; 【例】查询员工 及其 所属领导的名字&#xff08;managerid&#xff0c;领导也是员工表emp1表中的数据&#xff09; &#xff01;&#xff01;必须起别名&#xff01;&#xff01; ——内连接只查询交集部分的数据 …

grep命令的用法

文章目录 前言一、使用说明二、应用举例 前言 grep 命令用于查找文件里符合条件的字符串。 一、使用说明 -r: 如果需要搜索目录中的文件内容, 需要进行递归操作, 必须指定该参数 -i: 对应要搜索的关键字, 忽略字符大小写的差别 -n: 在显示符合样式的那一行之前&#xff0c;标…

基于MATLAB的径向基函数插值(RBF插值)(一维、二维、三维)

基于MATLAB的径向基函数插值&#xff08;RBF插值&#xff09;&#xff08;一维、二维、三维&#xff09; 0 前言1 RBF思路2 1维RBF函数2.1 参数说明2.1.1 核函数选择2.1.2 作用半径2.1.3 多项式拟合2.1.4 误差项&#xff08;光滑项&#xff09; 3 2维RBF函数4 3维RBF函数 惯例声…

AI 绘画Stable Diffusion 研究(十四)SD 图生图+剪映制作人物说话视频

大家好&#xff0c;我是风雨无阻。 前一篇&#xff0c;我们详细介绍了使用 SadTlaker制作数字人视频案例&#xff0c;感兴趣的朋友请前往查看:AI 绘画Stable Diffusion 研究&#xff08;十三&#xff09;SD数字人制作工具SadTlaker使用教程。 对于没有安装 SadTlaker 插件的朋友…

Vue2向Vue3过度核心技术生命周期

目录 1 Vue生命周期2 Vue生命周期钩子3 生命周期钩子小案例1.1 在created中发送数据1.2 在mounted中获取焦点 4 案例-小黑记账清单4.1 需求图示&#xff1a;4.2 需求分析3.思路分析4.代码准备 1 Vue生命周期 思考&#xff1a;什么时候可以发送初始化渲染请求&#xff1f;&#…

【算法专题突破】双指针 - 复写零(2)

目录 1. 题目解析 2. 算法原理 3. 代码编写 写在最后&#xff1a; 1. 题目解析 题目链接&#xff1a;1089. 复写零 - 力扣&#xff08;Leetcode&#xff09; 我先来读题&#xff0c; 题目的意思非常的简单&#xff0c;其实就是&#xff0c; 遇到 0 就复制一个写进数组&a…

ElementUI Table 翻页缓存数据

Element UI Table 翻页保存之前的数据,网上找了一些,大部分都是用**:row-key** 和 reserve-selection,但是我觉得有bug,我明明翻页了…但是全选的的个框还是勾着的(可能是使用方法不对,要是有好使的…请cute我一下…感谢) 所以自己写了一个… 思路: 手动勾选的时候,将数据保存…

jsp 图书销售系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 JSP 图书销售系统是一套完善的java web信息管理系统&#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为 TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.0&…

Vue实现Excel表格中按钮增加小数位数,减少小数位数功能,多用于处理金融数据

效果图 <template><div><el-button click"increaseDecimals">A按钮</el-button><el-button click"roundNumber">B按钮</el-button><el-table :data"tableData" border><el-table-column v-for&q…

POSTGRESQL 如何用系统函数来诊断权限问题

开头还是介绍一下群&#xff0c;如果感兴趣polardb ,mongodb ,mysql ,postgresql ,redis 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请联系 liuaustin3 &#xff0c;在新加的朋友会分到2群&#xff08;共…

win10 下运行 npm run watch-poll问题

背景&#xff1a;在本地练习laravel项目&#xff0c;windows 宝塔环境&#xff08;之前装过ubuntu子系统&#xff0c;很慢&#xff0c;就放弃了。有知道的兄弟说下&#xff0c;抱拳&#xff09;。以下命令我是在本地项目中用git bash里运行的&#xff0c;最好用管理员权限打开你…

ARM开发,stm32mp157a-A7核中断实验(实现按键中断功能)

1.实验目的&#xff1a;实现KEY1/LEY2/KE3三个按键&#xff0c;中断触发打印一句话&#xff0c;并且灯的状态取反&#xff1b; key1 ----> LED3灯状态取反&#xff1b; key2 ----> LED2灯状态取反&#xff1b; key3 ----> LED1灯状态取反&#xff1b; 2.分析框图: …