欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 科技 > 名人名企 > 【C++第十课 - stack_queue】stack、queue的使用、适配器模型stack、queue和priority_queue的底层实现、deque

【C++第十课 - stack_queue】stack、queue的使用、适配器模型stack、queue和priority_queue的底层实现、deque

2024/10/25 17:19:16 来源:https://blog.csdn.net/m0_60803455/article/details/139755310  浏览:    关键词:【C++第十课 - stack_queue】stack、queue的使用、适配器模型stack、queue和priority_queue的底层实现、deque

目录

  • 一、stack使用
    • 1、push
    • 2、pop
    • 3、empty
    • 4、top
    • 题目
      • 1、最小栈
      • 2、栈的压入、弹出序
      • 3、逆波兰表达式求值
  • 二、queue的使用
    • priority_queue
    • 习题
  • 三、适配器
    • stack的底层实现
    • queue的底层实现
    • priority_queue的底层实现
    • 仿函数/函数对象
    • 函数指针
  • 四、deque

一、stack使用

stack是个容器适配器
stack想要访问里面所有的数据必须pop和top,不能使用范围for

1、push

插入向量
在这里插入图片描述

	stack<int> s;s.push(1);s.push(2);s.push(3);s.push(4);

2、pop

移除栈顶数据
在这里插入图片描述

3、empty

stack为空返回true
stack非空返回false

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

4、top

取栈顶元素

题目

1、最小栈

https://leetcode.cn/problems/min-stack/
在这里插入图片描述
双栈解决
方案一
设计两个stack,一个stack存放数值,另一个stack存放最小值

存了这么多5有点浪费空间
改进方案二

在这里插入图片描述
方案二

_stpop的与_minst栈顶元素一样的时候,_minst也pop
存在的问题:当有好多个最小值是_minst要push进去多个,->改进:方案三

在这里插入图片描述

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()){_minst.pop();}_st.pop();}int top() {return _st.top();}int getMin() {return _minst.top();}
private:stack<int> _st;stack<int> _minst;
};

方案三
在这里插入图片描述

2、栈的压入、弹出序

用栈来模拟入栈和出栈过程

(1)如果pushV当前入栈的值和popV当前出栈的值一样,pushV向后移一位,popV向后移一位
(2)如果pushV当前入栈的值和popV当前出栈的值不一样,分两种情况
第一种情况:如果栈顶元素与popV当前出栈元素一样,popv向后移一位,栈顶元素弹出
第二种情况:如果栈为空或栈顶元素与popV当前的出栈元素不一样,将pushV当前入栈元素压入栈中,pushV向后移一位

之后开始对栈中元素按照popV的顺序进行出栈,如果对不上就是False

简化:先入栈,再判断

1、入栈序列当前数据入栈
2、栈顶元素与出栈序列进行比较
(1)相等,出栈,出栈序列++
(2)不相等
2的结束标志,栈为空或不相等
所有的结束标志:入栈序列走完

class Solution {
public:/*** 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可** * @param pushV int整型vector * @param popV int整型vector * @return bool布尔型*/bool IsPopOrder(vector<int>& pushV, vector<int>& popV) {// write code herestack<int> s;size_t pushi = 0;size_t popi = 0;while(pushi < pushV.size()){s.push(pushV[pushi]);while(!s.empty() && s.top() == popV[popi]){s.pop();++popi;}++pushi;}return popi == popV.size();}
};

3、逆波兰表达式求值

逆波兰表达式求值

前缀表达式(波兰)
所有的符号都是在要运算的操作数字的前面出现。例如 /++abcde
中缀表达式
所有的符号都是在要运算的操作数字的中间出现。例如(a+b+c
d)/e
后缀表达式(逆波兰)
所有的符号都是在要运算的操作数字的后面出现。例如 abcd*++e/

在这里插入图片描述

二、queue的使用

在这里插入图片描述

容器container默认是deque(双端队列)

在这里插入图片描述

priority_queue

不是先进先出,是按优先级出
底层是:堆
是适配器,不是容器了
compare是比较的函数

在这里插入图片描述
在这里插入图片描述

习题

在这里插入图片描述
方法一

在这里插入图片描述

class Solution {
public:vector<vector<int>> levelOrder(TreeNode* root) {queue<TreeNode*> q;queue<int> qlayer;vector<vector<int>> vv;int layer = 1;if(root){q.push(root);qlayer.push(layer);}while(!q.empty()){vector<int> v;while(qlayer.front() == layer ){TreeNode* cur = q.front();q.pop();v.push_back((*cur).val);if(cur->left){q.push(cur->left);qlayer.push(layer + 1);}if(cur->right){q.push(cur->right);qlayer.push(layer + 1);}qlayer.pop();}vv.push_back(v);++layer;}return vv;}
};

方法二

三、适配器

适配器就是一个设计模式
由容器(string、vector、list、deque)封装、转换而成的,底层数据的管理不是由自己负责的
默认容器:
stack -> deque
queue -> deque
priority_queue -> vector

stack的底层实现

站和队列的底层实现都是复用的容器(string、vector、list)

在这里插入图片描述

	template<class T, class Container = deque<T>>class stack{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_back();}const T& top(){return _con.back();}size_t size(){return _con.size();}bool empty(){return _con.empty();}private:Container _con;};
在这里插入代码片

queue的底层实现

在这里插入图片描述

	template<class T, class Container = deque<T>>class queue{public:void push(const T& x){_con.push_back(x);}void pop(){_con.pop_front();}const T& front(){return _con.front();}const T& back(){return _con.back();}size_t size(){return _con.size();}bool empty(){return _con.empty();}private:Container _con;};

priority_queue的底层实现

在这里插入图片描述
是优先级队列,优先级高的先出,因此用堆进行实现

	template<class T, class Container = vector<T>>class priority_queue{public:void adjust_up(){int child = _con.size() - 1;int parent = (child - 1) / 2;while (parent >= 0){if (_con[child] > _con[parent]){swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void push(const T& x){_con.push_back(x);adjust_up();}void adjust_down(){int parent = 0;int left = parent * 2 + 1; int right = parent * 2 + 2;int size = _con.size();while (left < size){int big = left;if (right < size && _con[right] > _con[left]){big = right;}if (_con[big] > _con[parent]){swap(_con[big], _con[parent]);parent = left;left = parent * 2 + 1;right = parent * 2 + 2;}else{break;}}}//优先出优先级高的void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjust_down();}const T& top(){return _con[0];}size_t size(){return _con.size();}bool empty(){return _con.empty();}private:Container _con;};

priority_queue里面用的仿函数–第三个模板参数

仿函数/函数对象

为了解决函数指针的缺陷
回调函数:这个函数已经写好了,在用到它的时候再去调它(C语言用这个)
Compare可以定义成成员对象,也可以在用的时候创建一个Compare com;
模板参数:传的是类型,编译的时候传递

namespace zyh
{template<class T>class less{public:bool operator()(T x, T y){return x < y;}};template<class T>class greater{public:bool operator()(T x, T y){return x > y;}};template<class T, class Container = vector<T>, class Compare = greater<T>>class priority_queue{public:void adjust_up(){int child = _con.size() - 1;int parent = (child - 1) / 2;while (parent >= 0){if (_com(_con[child], _con[parent])){swap(_con[child], _con[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}}void push(const T& x){_con.push_back(x);adjust_up();}void adjust_down(){int parent = 0;int left = parent * 2 + 1; int right = parent * 2 + 2;int size = _con.size();while (left < size){int big = left;if (right < size && _com(_con[right], _con[left])){big = right;}if (_com(_con[big], _con[parent])){swap(_con[big], _con[parent]);parent = left;left = parent * 2 + 1;right = parent * 2 + 2;}else{break;}}}//优先出优先级高的void pop(){swap(_con[0], _con[_con.size() - 1]);_con.pop_back();adjust_down();}const T& top(){return _con[0];}size_t size(){return _con.size();}bool empty(){return _con.empty();}private:Container _con;Compare _com;};
}

在这里插入图片描述
模板参数不仅能在类里面传递还能在函数里面传递
在这里插入图片描述

上面是类模板,只能穿仿函数。如果传函数指针,类里面也是将它转换成类型还是拿不到函数指针
下面是函数模板,可以传仿函数对象、函数指针。能传函数指针是因为,可以根据函数指针推出类型,同时参数那也可以得到函数指针。

函数指针

传递的是对象是参数变量,运行时传递的

在这里插入图片描述

四、deque

双端队列,但不是队列。就像优先级队列也不是队列

拥有list和vector的所有功能,尾插尾删、头插头删、[ ]
[ ]的效率没有vector的高

vector
优点:物理结构连续存储的优势
(1)下标随机访问
(2)缓存命中高
缺点:
(1)前面插入删除效率低
(2)扩容有消耗
list
优点:
(1)扩容没有消耗
(2)随机插入删除效率高
缺点:
(1)不支持下标随机访问
(2)缓存命中低

在这里插入图片描述

deque
优势:头插头删,尾插尾删很不错
不足:
随机访问效率没有vector高
访问第i个值,【假设保持每个buff一样大,都是10】
如果第一个buff不是从头开始的,不在第一个buff,那么i -= 第一个buff的数据个数
第i/10个buff中
在这个buff的第i%10位置
中间插入删除如何实现?
如果不需要保持每个buff一样大,只能挪动数据
如果不需要保持每个buff一样大,可以对当前buff,扩容或者挪动数据

结论
1、小标随机访问,效果不错,但是跟vector仍有差距
2、中间插入删除,效率差

如果一个适配器经常头插头删、尾插尾删 -> deque
如果少量的下标访问 -> 可以用deque
如果大量的下标访问 -> 需要用vector
如果中间插入删除 -> list

在这里插入图片描述

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com