概念
我们可以简单的将容器适配器当做一个接口装置。有的电脑上没有数据转接口,但是有usb接口,这是我们没必要重新买一个电脑,我们可以做一个usb数据转接线。而这根数据转接线就类似于适配器一样。
在C++中,我们已经有了(vector、list、deque等容器)插入、删除、迭代器就电脑usb接口,当我们想要实现栈的操作时,我么没有必要再重新写新的数据结构,只需要将其接口进行重新的封装,相当于做了一根数据转接线。我们就可以将这个容器当做数据结构使用。
分类
C++中定义了3种容器适配器,它们让容器提供的接口变成了我们常用的的3种数据结构,stack(栈)、queue(队列)、priority_queue(优先级对列)
- 栈:先进后出,我们可以想一下,在STL中,其底层应该一些序列式中容器,能够进行提供push_back(向栈顶插入元素) 、pop_back(删除栈顶元素)序列式容器都可以满足封装成栈的要求。
- 队列:先进先出。对pop_front(头删)、push_back(尾插)操作的序列式容器的封装,底层不可能是vector。
- 优先级队列:支持随机访问的功能,所以其底层结构只能为vector或duque。
接口
stack(栈)接口
qeque(队列)接口
priority_queue(优先级对列)
底层结构
stack:deque
queue:deque
priority_queue:vector,默认大顶堆
为什么stack与queue底层为deque,priority_queue底层为vector?
deque于vector的区别:
列举了几个重要的信息:我们现在了解到为啥stack、queue、priority_queue底层实现不同。
- stack、queue不需要进行元素遍历,但是元素入栈、入队容易发生扩容操作,所以使用deque。在stack中元素增长时,deque比vector的效率高;queue中的元素增长时,deque不仅效率高,而且内存使用率高。
- priority_queue需要对元素进行遍历,vector迭代器的速度相对于duque来说比较快。
stack模拟实现
template<class T,class S = deque<T>>
class Stack
{
public:
Stack()
{
}
void push(const T& x)
{
_s.push_back(x);
}
void pop()
{
_s.pop_front();
}
T& top() //这块需要注意,由于栈是先进后出,这块于deque的刚好相反
{
return _s.back();
}
size_t size()
{
return _s.size();
}
bool empty()
{
return _s.empty();
}
private:
S _s;
};
queue模拟实现
{
template<class T, class D = deque<T>>
class queue
{
public:
queue()
{}
void push(const T& data)
{
_d.push_back(data);
}
void pop()
{
_d.pop_front();
}
T& top()
{
return _d.front();
}
size_t size()
{
return _d.size();
}
bool empty()
{
return _d.empty();
}
T& back()
{
return _d.back();
}
private:
D _d;
};
}
priority_queue模拟实现
#pragma once
#include<iostream>
#include<vector>
using namespace std;
template<class T,class Com=less<T> >
class mpriority_queue
{
public:
mpriority_queue()
{}
template<class Iterator>
mpriority_queue(Iterator first, Iterator last)
:con(first,last)
{
//从哪里开始调整:倒数第一个非叶子节点
int root = ((con.size() - 1) - 1) / 2;
for (; root >= 0; root++)
{
adjustdown(root);
}
}
void push(const T& data)//需要向上调整
{
//先将data放入最后,然后进行向上调整
con.push_back(data);
size_t chlid = (con.size() - 1);
size_t parent = (chlid - 1) / 2;
Com com;
while (chlid)
{
if (com(con[parent] , con[chlid]))
{
swap(con[chlid], con[parent]);
chlid = parent;
parent = (chlid - 1) / 2;
}
else
return;
}
}
void pop()//需要向下调整
{
//堆中的删除一定删除的是堆顶元素
if (con.empty())
return;
swap(con.front(), con.back());
con.pop_back();
adjustdown(0);
}
const T& top()const
{
return con.front();
}
bool empty()const
{
return con.empty();
}
const size_t Size()const
{
return con.size();
}
private:
//向下调整时间复杂度为(o(logN))
void adjustdown(size_t parent)
{
size_t chlid = parent * 2 + 1;
Com com;
while (com(chlid , con.size()))
{
if (com(chlid+1,con.size()) && com(con[chlid] , con[chlid + 1]))
chlid = chlid + 1;
if (com(con[parent] , con[chlid]))
{
swap(con[chlid], con[parent]);
parent = chlid;
chlid = parent * 2 + 1;
}
else
return;
}
}
vector <T> con;
};
template<class T>
class great
{
public:
bool operator()(T left, T right)
{
return left > right;
}
};
void test()
{
mpriority_queue<int,great<int> > q;
q.push(5);
q.push(1);
q.push(6);
q.push(0);
q.push(2);
q.push(4);
q.push(3);
cout << q.Size()<<endl;
cout << q.top()<<endl;
q.pop();
cout << q.top()<<endl;
}