概述
????????????各位大佬大家好,我是猪皮兄弟????????????
文章目录
- 一、stack、queue的使用
- 二、模拟实现
- 一、容器适配器
- 二、stack、queue模拟
- stack模拟
- queue模拟
- 三、deque
- 1. operator[]
- 2.设计的缺陷
- 3.结论
- 四、优先级队列priority_queue
- 1.priority_queue的使用
- 2.priority_queue的模拟实现
- 五、仿函数
一、stack、queue的使用
leetcode-最小栈
要求时间复杂度O(1)
所以用一个正常栈和一个辅助栈来完成
st: 4 3 5 6 1
minst:4 3 1
即可,因为要取最小元素的话,必须删除掉5 6才能够拿到4 3,所以5 6没必要存入最小栈。
class MinStack {
public:
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;
};
nowcoder-栈的压入、弹出序列
这道题模拟的是入栈和出栈的过程,用一个栈来实现模拟
class Solution {
public:
bool IsPopOrder(vector<int> pushV,vector<int> popV) {
stack<int> st;
int popi=0;
for(auto& i :pushV)
{
st.push(i);
while(popi<popV.size()&&!st.empty()&&st.top()==popV[popi])
{
st.pop();
popi++;
}
}
return st.empty();
}
};
二、模拟实现
一、容器适配器
适配器是一种设计模式(设计模式是一套被反复使用的,被多数人知晓的、经过分类编目的,代码设计经验的总结),该种模式是将一个类的接口转换成客户端希望的另一个接口。
二、stack、queue模拟
栈和队列是没有迭代器的,因为需要保持它的特性,所以用不了迭代器
stack和queue是容器适配器,
关键是==复用==
stack模拟
namespace zhupi
{
template<class T,class Container = deque<T>>//双端队列,下面会说
class Stack
{
public:
void push(const T& x)
{
_con.push_back(x);
}
void pop()
{
_con.pop_back()
}
T&top()
{
return _con.back();
}
const T&top() const
{
return _con.back();
}
bool empty() const
{
return _con.empty();
}
size_t size() const
{
return _con.size();
}
private:
Container _con;
};
}
queue模拟
Queue不能够使用vector进行适配,因为vector不提供pop_front接口
namespace zhupi
{
template<class T,class Container=deque<T>>
class Queue
{
void push(const T& x)
{
_con.push_back(x);
}
void pop()
{
_con.pop_front();
}
T&front()
{
return _con.front();
}
const T&front() const
{
return _con.front();
}
T&back()
{
return _con.back();
}
const T&back() const
{
return _con.back();
}
bool empty() const
{
return _con.empty();
}
size_t size() const
{
return _con.size();
}
private:
Container _con;
};
}
三、deque
deque是一个双端开口的队列
deque由一个个小数组buffer构成,buffer数组有一定的大小,拥有一个中控(中央控制指针数组)来存每个数组,其次,头插的位置由特定的数据结构来完成
1. operator[]
(i-第一个buffer)/8就可以知道在第几个
(i-第一个buffer)%8就可以知道在那个buffer的第几个
2.设计的缺陷
1.operator[]的计算相比于vector[],大量使用的时候性能太低
(release几乎性能降低一般,debug差距 更大)
2.中间的插入删除效率很低,挪数据
3.底层角度,迭代器会很复杂
迭代器设计:四个指针first,last,cur,node
first,last指向开始和结束,cur指向现在的buffer的首地址,node指针取访问中控指针数组获得buffer位置
3.结论
1.真正适合的场景是头尾的插入删除(相比vector和list而言),所以,deque很适合做stack和 queue的默认适配容器。
2.中间插入删除就多用list
3.随机访问尽量用vector
四、优先级队列priority_queue
优先级队列其实是一个堆,所以,默认适配容器是vector
priority_queue也是不支持迭代器的,因为需要保证优先级
默认是大的优先级高(大堆)
priority_queue的仿函数比较的是优先级,也就是权重,所以less出来的是大堆,greater出来的是小堆
1.priority_queue的使用
#include <queue>
void test_priority_queue1()
{
priority_queue<int> pq;
pq.push(1);
pq.push(2);
pq.push(3);
//因为不支持迭代器,而且是堆,所以
while(!pq.empty())
{
cout<<pq.top()<<" ";
pq.pop();
}
}
void test_priority_queue1()
{
int a = {3,2,7,6,0,4,1,9,8,5};
//迭代区间构造,数组的迭代器是原生指针
priority_queue<int> heap(a,a+sizeof(a)/sizeof(int));
// priority_queue<int,vector<int>,less<int>>
//遍历
}
leetcode-数组中的第k个最大元素
要求时间复杂度O(n),找topK当然是用堆,向下调整建堆时间复杂度O(n)
class Solution{
public:
int fineKthLargest(vector<int>&nums,int k){
priority_queue<int> pq(num.begin(),nums.end());
while(--k)
{
pq.pop();
}
return pq.top();
}
};
2.priority_queue的模拟实现
主要是adjust_up和adjust_down函数
向下调整是从最后一个结点的父节点开始
1.即(child-1)/2
2.向下调整建堆因为跳过了 很多结点,几乎是1/2,所以能达到O(N)的时间复杂度
#include<vector>
namespace zhupi
{
template<class T,class Container=vector<T>,class Compare=std::less<int>>
class priority_queue
{
template<class InputIterator>
//迭代区间初始化,向下建堆
priority(InputIterator first,InputIterator last)
{
while(first!=last)
{
_con.push_back(*first);
}
//向下建堆从最后一个叶子结点的父节点开始
//left_child = parent*2+1;
//parent = (child-1)/2
for(int i=(_con.size()-1-1)/2;i>=0;i--)
{
adjust_down(i);
}
}
//暂时是大堆
class
void adjust_up(int child)
{
Compare com;
int parent = (child-1)/2;
while(parent)
{
if(com(_con[parent],_con[child]))//仿函数com
{
std::swap(_con[child],_con[parent]);//仿函数 com
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;
if(child+1)<_con.size()&&com(_con[child],_con[child+1]))//仿函数com
child++;
if((_con[child]<_con[parent]))//仿函数 com
{
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];
}
bool empty() const
{
return _con.empty();
}
size_t size() const
{
return _con.size();
}
private:
Container _con;
};
}
五、仿函数
STL六大组件之一,仿函数其实是一个类,类里面重载运算符() operator(),使得该类的对象能像函数一样的去调用。
template<class T>
class Less
{
public:
bool operator()(const T& l,const T& r) const
{
return l<r;
{
};
template<class T>
class Greater
{
public:
bool operator()(const T& l,const T& r) const
{
return l>r;
{
};
int main()
{
Less<int> lsFunc;
cout<<lsFunc(1,2);//像函数一样的去访问
Greater<int> gtFunc;
cout<<gtFunc(1,2);
return 0;
}
最后
以上就是单纯早晨为你收集整理的stack,queue,deque,priority_queue与仿函数一、stack、queue的使用二、模拟实现三、deque四、优先级队列priority_queue五、仿函数的全部内容,希望文章能够帮你解决stack,queue,deque,priority_queue与仿函数一、stack、queue的使用二、模拟实现三、deque四、优先级队列priority_queue五、仿函数所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复