栈的补充知识
- C++中stack 是容器么?
栈是以底层容器完成其所有的工作,对外提供统一的接口,底层容器是可插拔的(也就是说我们可以控制使用哪种容器来实现栈的功能) 。所以STL中栈往往不被归类为容器,而被归类为container adapter(容器适配器)。栈提供push 和 pop 等等接口,所有元素必须符合先进后出规则,所以栈不提供走访功能,也不提供迭代器(iterator)。 不像是set 或者map 提供迭代器iterator来遍历所有元素。 - 我们使用的stack是属于哪个版本的STL?
- HP STL 其他版本的C++ STL,一般是以HP STL为蓝本实现出来的,HP STL是C++ STL的第一个实现版本,而且开放源代码
- P.J.Plauger STL 由P.J.Plauger参照HP STL实现出来的,被Visual C++编译器所采用,不是开源的。
- SGI STL 由Silicon Graphics Computer Systems公司参照HP STL实现,被Linux的C++编译器GCC所采用,SGI STL是开源软件,源码可读性甚高。
3.我们使用的STL中stack是如何实现的?
我们常用的SGI STL,如果没有指定底层实现的话,默认是以deque为缺省情况下栈的底层结构。
SGI STL中 队列底层实现缺省情况下一样使用deque实现的。
std::stack<int, std::vector<int> > third; // 使用vector为底层容器的栈
std::queue<int, std::list<int>> third; // 定义以list为底层容器的队列
232.用栈实现队列
使用栈来模式队列的行为,如果仅仅用一个栈,是一定不行的,所以需要两个栈一个输入栈,一个输出栈
,这里要注意输入栈和输出栈的关系。
在push数据的时候,只要数据放进输入栈就好,但在pop的时候,操作就复杂一些,输出栈如果为空,就把进栈数据全部导入进来(注意是全部导入)
,再从出栈弹出数据,如果输出栈不为空,则直接从出栈弹出数据就可以了。
最后如何判断队列为空呢?如果进栈和出栈都为空的话,说明模拟的队列为空了。
C++实现
class MyQueue {
public:
stack<int> stIn;
stack<int> stOut;
MyQueue(){
}
// 添加元素到队列里面
void push(int x){
stIn.push(x);
}
int pop(){
// 判断出栈是否为空可以减少每次stackIn和stackOut的操作
if(stOut.empty()){
// 判断stackIn是否为空
while (!stIn.empty()){
stOut.push(stIn.top());
stIn.pop();
}
}
int result = stOut.top();
stOut.pop();
return result;
}
int peek(){
// 代码复用,直接使用已有的pop函数
int res = this->pop();
// 坑:不能使用this->push, 对stOut使用push
stOut.push(res);
return res;
}
bool empty(){
return stIn.empty() && stOut.empty();
}
};
Python实现
class MyQueue:
def __init__(self):
self.stack_in = []
self.stack_out = []
def push(self, x: int) -> None:
self.stack_in.append(x)
def pop(self) -> int:
"""
如果queue为空异常判断
"""
if self.empty():
return None
if self.stack_out:
return self.stack_out.pop()
else:
for i in range(len(self.stack_in)):
self.stack_out.append(self.stack_in.pop())
return self.stack_out.pop()
def peek(self) -> int:
"""
得到第一个元素
"""
ans = self.pop()
self.stack_out.append(ans)
return ans
def empty(self) -> bool:
"""
只要in或者out有元素,说明队列不为空
"""
return not (self.stack_in or self.stack_out)
225. 用队列实现栈
Note:很多算法题目主要是对知识点的考察和教学意义远大于其工程实践的意义,所以面试题也是这样!
使用一个队列模拟栈:一个队列在模拟栈弹出元素的时候只要将队列头部的元素(除了最后一个元素外) 重新添加到队列尾部,此时在去弹出元素就是栈的顺序了。
模拟示意图
C++实现
class MyStack {
public:
queue<int> que;
MyStack(){
}
void push(int x){
que.push(x);
}
// 思路:将队列里面前size-1个元素一次插向结尾
int pop(){
int size = que.size();
size--;
while (size--){
que.push(que.front());
que.pop();
}
int result = que.front();
que.pop();
return result;
}
// stack的头是queue的尾巴
int top(){
return que.back();
}
bool empty(){
return que.empty();
}
};
Python实现
class MyStack:
def __init__(self):
self.que = deque()
def push(self, x: int) -> None:
self.que.append(x)
def pop(self) -> int:
if self.empty():
return None
for i in range(len(self.que)-1):
self.que.append(self.que.popleft())
return self.que.popleft()
def top(self) -> int:
if self.empty():
return None
return self.que[-1]
def empty(self) -> bool:
return not self.que
`