stack&&queue的使用
stack的定义
方式一: 使用默认的适配器定义栈。
stack<int> stk;
方式二: 使用特定的适配器定义栈。
stack<int, vector<int>> stk;
stack<int, list<int>> stk;
注意:如果没有指定适配器,默认使用deque
。
stack的使用
#include <iostream>
#include <stack>
using namespace std;
int main()
{
stack<int> st;
st.push(1);
st.push(2);
st.push(3);
st.push(4);
cout << st.size() << endl; //4
while (!st.empty())
{
cout << st.top() << " ";
st.pop();
}
cout << endl; //4 3 2 1
return 0;
}
queue的定义
方式一: 使用默认的适配器定义队列。
queue<int> q;
方式二: 使用特定的适配器定义队列。
queue<int, vector<int>> q;
queue<int, list<int>> q;
注意:如果没有指定适配器,默认使用deque
。
queue的使用
#include <iostream>
#include <queue>
using namespace std;
int main()
{
queue<int> q;
q.push(1);
q.push(2);
q.push(3);
q.push(4);
cout << q.size() << endl; // 4
while (!q.empty())
{
cout << q.front() << " ";
q.pop();
}
cout << endl; //1 2 3 4
return 0;
}
stack&&queue的模拟实现
一、容器适配器
1.什么是适配器
适配器是一种设计模式,该种模式是将一个类的接口转换成客户希望的另外一个接口。 而容器适配器就是通过底层封装一个容器来实现另一个容器的功能展示。
在STL中像stack
、queue
、priority_queue
都是容器的适配器。
在默认情况下,stack
和queue
都是使用deque
作为底层的数据结构,priority_queue
使用vector
作为底层的数据结构。
2.容器适配器如何选择底层数据结构?
我们这里就介绍一下deque
为何可以作为stack
和queue
的底层数据结构。
deque(双端队列):是一种双开口的"连续"空间的数据结构,双开口的含义是:可以在头尾两端进行插入和删除操作,且时间复杂度为O(1)。而且可以使用[]
随机访问任意元素。与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率比较高。
deque
既可以随机访问元素,又可以随机的掺入删除元素,看似很棒的一个容器,但是平常却很少使用。
deque
的缺点:
- 因为
deque
的底层实现非常的复杂,所以导致[]
访问元素的时候,不如vector
计算的快。 - 在任意位置插入元素的时候,不如
list
快。 - 所以在大量访问元素的时候,仍然使用
vector
,在大量插入元素的时候,仍然使用list
。 - 因为底层的实现,所以
deque
迭起起访问效率不高。
deque
的优点:
deque
在头尾两端的插入删除元素的效率还是很高的,这样就可以弥补vector
在头部位置操作的效率,并且deque
在扩容的时候,代价要比vector
小的多。- 而相比
list
,因为deque
的底层是连续的,所以deque
空间利用率比较高,空间碎片化小,缓存利用率高。
由于deque
在头尾部的操作效率比较高,而stack
和queue
都是线性的数据结构,功能基本上都是对于头尾部的操作,并且stack
和queue
都没有迭代器访问,所以使用deque
就是最好的选择了。
二、模拟实现
stack
和queue
都叫做容器的适配器,简单的来说就是,这个容器就是另一个容器的一个子集。通过封装了一个功能比较强大的容器,并只体现出这个封装容器的部分功能,从而得到了另一个容器,这就出现了容器的适配器。
如果没有指定适配器,stack
和queue
的底层默认使用deque
作为封装的容器。
#include <iostream>
#include <deque>
using namespace std;
namespace mystack {
template<class T, class Container = deque<T>>
class stack {
public:
stack() {
}
void push(const T& val) {
_container.push_back(val);
}
void pop() {
_container.pop_back();
}
T& top() {
return _container.back();
}
// 注意这里必须要这个接口
// 因为const对象返回的top()是不可以被修改的
const T& top() const {
return _container.back();
}
size_t size() const {
return _container.size();
}
bool empty() const {
return _container.empty();
}
private:
Container _container;
};
}
namespace myqueue
{
template<class T, class Container = deque<T>>
class queue {
public:
queue() {}
void push(const T& val) {
_container.push_back(val);
}
void pop() {
_container.pop_front();
}
T& back() {
return _container.back();
}
const T& back() const {
return _container.back();
}
T& front() {
return _container.front();
}
const T& front() const {
return _container.front();
}
size_t size() const {
return _container.size();
}
bool empty() const {
return _container.empty();
}
private:
Container _container;
};
void test() {
queue<int> q;
q.push(1);
q.push(2);
while (!q.empty()) {
cout << q.front();
q.pop();
}
}
}