栈与队列的示意图如下:
所以,栈是先进后出,队列是先进先出
- C++中stack 是容器么?
- 我们使用的stack是属于哪个版本的STL?
- 我们使用的STL中stack是如何实现的?
- stack 提供迭代器来遍历stack空间么?
(1)栈是以底层容器完成其所有的工作,对外提供统一的接口,底层容器是可插拔的(也就是说我们可以控制使用哪种容器来实现栈的功能)。
所以STL中栈往往不被归类为容器,而被归类为container adapter(容器适配器)。
(2)栈提供push 和 pop 等等接口,所有元素必须符合先进后出规则,所以栈不提供走访功能,也不提供迭代器(iterator)。 不像是set 或者map 提供迭代器iterator来遍历所有元素。
那么问题来了,STL 中栈是用什么容器实现的?
从下图中可以看出,栈的内部结构,栈的底层实现可以是vector,deque,list 都是可以的, 主要就是数组和链表的底层实现。
我们也可以指定vector为栈的底层实现,初始化语句如下:
std::stack<int, std::vector<int> > third; // 使用vector为底层容器的栈
队列中先进先出的数据结构,同样不允许有遍历行为,不提供迭代器, SGI STL中队列一样是以deque为缺省情况下的底部结构。
也可以指定list 为起底层实现,初始化queue的语句如下:
std::queue<int, std::list<int>> third; // 定义以list为底层容器的队列
232.用实现队列:
使用栈实现队列的下列操作:
push(x) -- 将一个元素放入队列的尾部。
pop() -- 从队列首部移除元素。
peek() -- 返回队列首部的元素。
empty() -- 返回队列是否为空。
可以借助两个栈实现队列的效果。
代码如下:
class MyQueue {
public:
stack<int, vector<int>>stIn; //使用容器定义一个进栈
stack<int, vector<int>>stOut;//使用容器定义一个出栈
queue<int, vector<int>>que;
//获取队列对头元素
void push(int x) {
stIn.push(x);//push函数代表从栈头出第一个元素
}
//实现弹出队头元素
int pop() {
if (stOut.empty()) {
while (!stIn.empty()) {
stOut.push(stIn.pop());//stOut栈添加从stIn栈弹出的元素
stIn.push(); //继续向stIn添加元素
}
}
int result = stOut.top();
stOut.pop();//弹出stOut栈头元素,实际上这个就相当于队列的头元素
return result;
}
//获取队列头部元素
int peek() {
int res = this->pop();
stOut.push(res);
return res;
}
//是否为空
bool empty() {
return stIn.empty() && stOut.empty();
}
};
225.用队列实现栈操作
使用队列实现栈的下列操作:
- push(x) -- 元素 x 入栈
- pop() -- 移除栈顶元素
- top() -- 获取栈顶元素
- empty() -- 返回栈是否为空
注意:
- 你只能使用队列的基本操作-- 也就是 push to back, peek/pop from front, size, 和 is empty 这些操作是合法的。
- 你所使用的语言也许不支持队列。 你可以使用 list 或者 deque(双端队列)来模拟一个队列 , 只要是标准的队列操作即可。
- 你可以假设所有操作都是有效的(例如, 对一个空的栈不会调用 pop 或者 top 操作)。
代码如下:
class MyStack {
public:
//用一个对列
queue<int,vector<int>>q;
//弹出栈顶元素
int pop() {
int size = q.size();
size--;//实际上,size先减1,就是为了队尾(也就是栈顶元素)在队列的最低下
while (size--) {
int top_q = q.front();
q.push(top_q); //不断弹出队首元素(只剩下原来的队尾)
q.pop();//在 C++ 标准库中,std::queue 类的 pop() 函数是不接受任何参数的。pop() 函数用于在队列头部移除掉第一个元素,使得队列的大小减 1。函数没有返回值,处理完毕后队列被改变。
// 因此,当使用 std::queue 类时,pop() 函数的括号里面不能填写任何参数,否则会出现编译错误。如果需要在队列中删除指定位置的元素,可以使用其他容器,如 std::list 或 std::deque,并使用其提供的 erase() 函数来实现。
}
int result = q.front();
q.pop();
return result;
}
//将x入栈
void push(int x) {
q.push(x);
}
//获取栈顶元素
int top() {
return q.back();
}
bool isempty() {
return q.empty();
}
};