目录
在前面分别讲了线性结构栈和队列,了解了栈和队列的实现基本原理。
栈的特点是:先进后出,后进先出。
队列的特点是:先进先出,后进后出。
那么如何用栈来实现队列呢?
首先我们可以知道栈存储元素,先进去的元素一定是在栈底,而在队列中先进去的元素一定是队头。要把这两者联系起来。那么要实现栈底元素对应队头元素,我们可以把栈想象成汉诺塔,要取出最底的圆盘,那么必须先取出上面的圆盘依次放到另一根杆上。这里可以把存储元素的栈比喻成A杆,而我们要取最下面的圆盘时用于存放元素的栈比喻为B杆。那么当我们插入元素时,就往A杆放圆盘,当我们要取队头元素也就是这里的A杆的栈底元素,先确认B杆是否有圆盘,如果没有圆盘那么就把A杆的圆盘依次从上往下往B杆放。此时A杆的最下面的圆盘就是B杆最上面的圆盘。如果B杆有圆盘,那么新放入的圆盘还是放在A杆,以保证放入圆盘的顺序不被打乱。
从上述描述,我们可以知道用栈实现队列的话,可以使用两个栈,一个栈用于辅助,一个栈用于操作。
基本流程如下:
元素依次入栈。如果要进行出队头,此时队头在栈底,需要将栈的元素,依次出栈,放到另一个辅助栈中。依次入栈后,辅助栈的栈顶就是队头。然后需要将辅助栈中的元素依次出栈,放到原栈中。
这种方法的:push时间复杂度为O(1),pop的时间复杂度为O(n),peek(查看队头元素)的时间复杂度为O(n),empty的时间复杂度为O(1)。
这里我们可以知道实现队列的出队和获取队头元素的时间复杂度都是O(n),那么我们可不可以进行优化,以此来达到趋近O(1)的时间复杂度呢?
优化:
让pop和peek均摊时间复杂度(只有辅助栈为空时,需要把主栈的元素导入辅助栈,此时时间复杂度为O(n),而辅助栈不为空,对队头进行出栈或者是查看队头元素时间复杂度都是O(1))。
push:先放入元素,如果没有其他操作,入队的元素都入栈主栈中。
pop:把主栈中的元素出栈,(如果辅助栈为空)全部导入到辅助栈中,直接从辅助栈中的栈顶做出队操作或者是peek操作。
empty:主栈为空并且辅助栈也为空,那么队列为空。
#include <iostream>
#include <stack>
using namespace std;
class NewQueue{
public:
NewQueue():queue_size(0){}
~NewQueue(){}
void push(int value){
st1.push(value);
queueu_size++;
}
void pop(){
if(st2.empty()){
if(st1.empty()){
throw "queue is empty!";
}
while(!st1.empty()){
st2.push(st1.top());
st1.pop();
}
}
st2.pop();
queue_size--;
}
int front(){
if(st2.empty()){
if(st1.empty()){
throw "queue is empty!";
}
while(!st1.empty()){
st2.push(st1.top());
st1.pop();
}
}
return st2.top();
}
int back(){
if((st1.empty())&&(st2.empty())){
throw "queue is empty!";
}
return number;
}
int size()const{
return count;
}
bool empty(){
return st1.empty()&&st2.empty();
}
private:
stack<int> st1;
stack<int> st2;
int number;
int queue_size;
};
int main(){
NewQueue q;
}