栈和队列
栈是一个非常常见的数据结构,它在计算机领域被广泛应用,比如操作系统会给每个线程创建一个栈来存储函数调用时各个函数的参数、返回地址及临时变量等。
栈是一种先进后出的数据结构,元素从顶端入栈,然后从顶端出栈。
通常栈是一个不考虑排序的数据结构,我们需要 O ( n ) O(n) O(n)的时间才能找到栈中最大或最小的元素。
队列是另外一种很重要的数据结构。队列的特点是先进先出。在树的宽度优先遍历算法中,我们在遍历某一层树的节点时,把节点的子节点放到一个队列里,以备下一层节点的遍历。
队列是一种先进先出的数据结构,元素从后端入队,然后从前端出队。
栈和队列虽然是特点针锋相对的两个数据结构,但是有意思的是他们却相互联系。比如下题:
9 用两个栈实现队列
双栈可以实现列表倒序。栈A一直放数据,如果要删除数据的话,将栈A的内容放入栈B,这时从栈B删除就是删除栈A栈顶的元素。如果栈A再加入新的元素,当他们再次放到栈B时,顺序和队列是一样的。删除完栈B的元素,就说明这个队列前部分删除完了,要删除后一部分了,这时从栈A(如果还有元素的话)将后一部分放入栈B,接着删除。
class CQueue {
public:
stack<int> A;
stack<int> B;
CQueue() {
}
void appendTail(int value) {
A.push(value);
}
int deleteHead() {
if(A.empty() && B.empty()){
return -1;
}
else if(B.empty()){//B空,把A中的全倒序放入B中
while(!(A.empty())){
B.push(A.top());
A.pop();
}
//倒序放入完成之后,B的栈顶元素删除,B的元素删完再从A拿进来!!!
}
int res=B.top();
B.pop();
return res;
}
};
/**
* Your CQueue object will be instantiated and called as such:
* CQueue* obj = new CQueue();
* obj->appendTail(value);
* int param_2 = obj->deleteHead();
*/
255 用队列实现栈
思路:两个队列,总是至少有一个保持是空的状态。将元素压入栈顶时,将元素入非空队列就好。top时,将非空队列除了头元素,全部放入空队列,返回头元素并将头元素放入上面的非空队列,pop时删除这个元素就好。
缺点:top和pop操作时间复杂度较高是
O
(
n
)
O(n)
O(n)。要先放入非空队列。插入操作时间复杂度是
O
(
1
)
O(1)
O(1),直接放入就好。
class MyStack {
public:
deque<int> A;
deque<int> B;
/** Initialize your data structure here. */
MyStack() {
}
/** Push element x onto stack. */
void push(int x) {
if(A.empty()){//A队列空,放入B
B.push_back(x);
}
else{//A不空,放入A
A.push_back(x);
}
}
/** Removes the element on top of the stack and returns that element. */
int pop() {
if(A.empty() && B.empty()){
return -1;
}
if(A.empty()){//A空,转到A,然后删除
int itr = B.size();
for(int i=0;i<itr-1;i++){
A.push_back(B.front());
B.pop_front();
}
//B还剩一个元素,返回并删除
int res = B.front();
B.pop_front();
return res;
}else{
int itr=A.size();
for(int i=0;i<itr-1;i++){
B.push_back(A.front());
A.pop_front();
}
//B还剩一个元素,返回并删除
int res = A.front();
A.pop_front();
return res;
}
}
/** Get the top element. */
int top() {
if(A.empty() && B.empty()){
return -1;
}
if(A.empty()){//A空,转到A,
int itr=B.size();
for(int i=0;i<itr-1;i++){//B的size 改变了
A.push_back(B.front());
B.pop_front();
}
//B还剩一个元素,返回
int res = B.front();
A.push_back(res);
B.pop_front();
return res;
}else{
int itr=A.size();
for(int i=0;i<itr-1;i++){
B.push_back(A.front());
A.pop_front();
}
//B还剩一个元素,返回
int res = A.front();
B.push_back(res);
A.pop_front();
return res;
}
}
/** Returns whether the stack is empty. */
bool empty() {
if(A.empty() && B.empty()){//A,B都空
return true;
}
else{
return false;
}
}
};
/**
* Your MyStack object will be instantiated and called as such:
* MyStack* obj = new MyStack();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->top();
* bool param_4 = obj->empty();
*/
这个代码的push操作时间复杂度是
O
(
n
)
O(n)
O(n),而top和pop操作的时间复杂度都是
O
(
n
)
O(n)
O(n)。只要确保队列A中队首元素总是栈顶元素即可。
class MyStack {
public:
/** Initialize your data structure here. */
deque<int> A;
deque<int> B;
MyStack() {
}
/** Push element x onto stack. */
void push(int x) {
B.push_back(x);
while(!A.empty()){
B.push_back(A.front());
A.pop_front();
}
swap(A,B);
}
/** Removes the element on top of the stack and returns that element. */
int pop() {
if(A.empty()){
return -1;
}
int res = A.front();
A.pop_front();
return res;
}
/** Get the top element. */
int top() {
if(A.empty()){
return -1;
}
return A.front();
}
/** Returns whether the stack is empty. */
bool empty() {
if(A.empty()){
return true;
}
return false;
}
};
/**
* Your MyStack object will be instantiated and called as such:
* MyStack* obj = new MyStack();
* obj->push(x);
* int param_2 = obj->pop();
* int param_3 = obj->top();
* bool param_4 = obj->empty();
*/