stack和queue是作为STL的容器适配器被实现的,容器适配器暨是对特定类封装作为其底层的容器,并提供一组特定的成员函数来访问其元素,将特定类作为其底层。
先来看一下MSDN里面对stack的简单介绍
我们再来看一下stack简单的使用。
void main()
{
stack<int> st;//容器适配器
for (int i = 1; i <= 10; ++i)//将1到10顺序入栈
{
st.push(i);
}
cout << "st.size = " << st.size() << endl;
while (!st.empty())//顺序出栈
{
int value = st.top();
st.pop();
cout << value << endl;
}
//无法通过迭代器访问
}
给个题理解一下。
155.最小栈
题解:
class MinStack {
public:
/** initialize your data structure here. */
MinStack()
{
}
void push(int val)
{
data_st.push(val);
if(min_st.empty() || val<=min_st.top())
min_st.push(val);
}
void pop()
{
int val = data_st.top();
data_st.pop();
if(val == min_st.top())
min_st.pop();
}
int top()
{
return data_st.top();
}
int getMin()
{
return min_st.top();
}
private:
stack<int> data_st;
stack<int> min_st;
};
从栈的接口中可以看出,栈实际是一种特殊的vector,因此使用vector完全可以模拟实现stack。
namespace LJL
{
template<class _Ty>
class stack
{
public:
stack()
{
}
~stack()
{
}
public:
bool empty()const
{
return _C.empty();
}
size_t size()const
{
return _C.size();
}
_Ty& top()
{
return _C.back();
}
const _Ty& top()const
{
return _C.back();
}
void push(const _Ty &x)
{
_C.push_back(x);
}
void pop()
{
_C.pop_back();
}
private:
vector<_Ty> _C;//若要使用list模拟只需要把vector改为list
};
}
注意这里的msdn有误,队列无top一说,队列的队头为front
代码演示:
void main()
{
queue<int> q;//容器适配器
for (int i = 1; i <= 10; ++i)//将1到10顺序入栈
{
q.push(i);
}
cout << "q.size = " << q.size() << endl;
while (!q.empty())//顺序出栈
{
int value = q.front();
q.pop();
cout << value << endl;
}
//无法通过迭代器访问
}
因为queue的接口中存在头删和尾插,因此使用vector来封装的效率太低,故可以借助list来模拟实现。
代码如下:
#include
namespace LJL
{
template<class T>
class queue
{
public:
queue() {
}
void push(const T& x) {
_c.push_back(x); }
void pop() {
_c.pop_front(); }
T& back() {
return _c.back(); }
const T& back()const {
return _c.back(); }
T& front() {
return _c.front(); }
const T& front()const {
return _c.front(); }
size_t size()const {
return _c.size(); }
bool empty()const {
return _c.empty(); }
private:
list<T> _c;
};
}
在系统中stack和queue是用容器双端队列deque来模拟的。
#include
namespace LJL
{
template<class _Ty,class Cont=deque<_Ty>>
class stack
{
public:
stack()
{
}
~stack()
{
}
public:
bool empty()const
{
return _C.empty();
}
size_t size()const
{
return _C.size();
}
_Ty& top()
{
return _C.back();
}
const _Ty& top()const
{
return _C.back();
}
void push(const _Ty &x)
{
_C.push_back(x);
}
void pop()
{
_C.pop_back();
}
private:
Cont _C;
};
template<class _Ty, class Cont=deque<_Ty>>
class queue
{
public:
queue()
{
}
~queue()
{
}
public:
bool empty()const
{
return _C.empty();
}
size_t size()const
{
return _C.size();
}
_Ty& front()
{
return _C.front();
}
_Ty& back()
{
return _C.back();
}
void pop()
{
_C.pop_front();
}
void push(const _Ty &x)
{
_C.push_back(x);
}
private:
Cont _C;
};
}
是一种双开口的“连续”空间的数据结构(实际并不是连续的,而是由一段段连续的小空间拼接而成的,类似于一个动态的二维数组),可以再头尾两端进行插入和删除操作,且时间复杂度为O(1)而vector为O(n),与vector比较,头插效率高,不需要搬移元素;与list比较,空间利用率较高,因为list不仅存储数据而且还需存储前后关系指针。
相对于普通queue而言,deque既可以尾插也可以头插,既可以头删也可以尾删。而queue只能尾插和头删。
代码演示:
void main()
{
deque<int> dq;
for (int i = 1; i <= 3; ++i)
{
dq.push_back(i);//尾插
}
for (int i = 3; i >= 1; --i)
{
dq.push_front(i);//头插
}
for (const auto & e : dq)
{
cout << e << " ";
}
cout << endl;
while (!dq.empty())
{
cout << dq.back() << endl;
dq.pop_back();
}
}
deque的缺陷:
不适合遍历,因为在遍历时,deque的迭代器要频繁检测其是否移动到某段小空间的边界,导致效率低下,目前对于queue的应用主要为stack和queue的底层数据结构。