(题目来源:力扣LeetCode)
包括:225、用队列实现一个栈 232、用栈实现一个队列
写在前面:队列和栈的特点刚好相反
队列(Queue)先进先出(First-in First-out);
栈(Stack)后进先出(Last-in First-out)
问题:如何是转换两者呢?答:使用两个队列/栈
题目:请你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通队列的全部四种操作(push、top、pop 和 empty)。
实现 MyStack 类:
void push(int x) 将元素 x 压入栈顶。
int pop() 移除并返回栈顶元素。
int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
示例:
输入:
["MyStack", "push", "push", "top", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 2, 2, false]
解释:
MyStack myStack = new MyStack();
myStack.push(1);
myStack.push(2);
myStack.top(); // 返回 2
myStack.pop(); // 返回 2
myStack.empty(); // 返回 False
详解:
class MyStack {
//类的属性
Queue<Integer> queue1;
Queue<Integer> queue2;
//初始化构造函数
public MyStack() {
queue1= new LinkedList<Integer>();
queue2= new LinkedList<Integer>();
}
//入栈方法
public void push(int x) {
queue2.offer(x);
while(!queue1.isEmpty()){
queue2.offer(queue1.poll());
}
//精髓,交换队列(空间换时间)
Queue<Integer> temp = queue1;
queue1 = queue2;
queue2 = temp;
}
//出栈方法
public int pop() {
return queue1.poll();
}
//查看栈顶元素
public int top() {
return queue1.peek();
}
//判断为空
public boolean empty() {
return queue1.isEmpty();
}
}
本题小结:
本题用了一个主队列和一个辅助队列实现了,栈的操作。其实就是当元素入队时对当前元素进行重新排序,使队列从先进先出的顺序变成先进后出的顺序。
在实现入栈方法的时候,将新入队的元素放入辅助队列中,并且进行重新排序使元素的顺序反转,然后使用了temp直接交换两个队列,而不是通过遍历交换两队列中的元素,使用空间换了时间。
题目:请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty):
实现 MyQueue 类:
void push(int x) 将元素 x 推到队列的末尾
int pop() 从队列的开头移除并返回元素
int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false
示例:
输入:
["MyQueue", "push", "push", "peek", "pop", "empty"]
[[], [1], [2], [], [], []]
输出:
[null, null, null, 1, 1, false]
解释:
MyQueue myQueue = new MyQueue();
myQueue.push(1); // queue is: [1]
myQueue.push(2); // queue is: [1, 2] (leftmost is front of the queue)
myQueue.peek(); // return 1
myQueue.pop(); // return 1, queue is [2]
myQueue.empty(); // return false
详解:
class MyQueue {
Stack<Integer> instack;
Stack<Integer> outstack;
public MyQueue() {
instack=new Stack<>();
outstack=new Stack<>();
}
public void push(int x) {
instack.push(x);
}
public int pop() {
if(outstack.isEmpty()){
while(!instack.isEmpty())
outstack.push(instack.pop());
}
return outstack.pop();
}
public int peek() {
if(outstack.isEmpty()){
while(!instack.isEmpty())
outstack.push(instack.pop());
}
return outstack.peek();
}
public boolean empty() {
return instack.isEmpty() && outstack.isEmpty();
}
}
本题小结:本题是使用栈实现队列的相关方法,思想与上一题类似,不过也有不同的解法。本题可以使用栈的使用,可以用两个栈,直接对栈内所有的元素进行反转。
比如:元素的入栈顺序是1,2,3.那么他们在经过第一个栈的出栈之后就变成了3,2,1.此时从第一个栈内出栈的元素再进第二个栈,那么此时的入栈顺序就是3,2,1.经过第二个栈的出栈之后就是1,2,3了。如此就完成了栈内元素的反转了。
值得注意的是,当第二个栈中有元素时,又需要新添加元素,必须先将第二个栈中的元素弹出,直到第二个栈为空时,才能将新元素放入第二个栈中
总结:
1、队列和栈的特点相反,队列先进先;栈先进后出,,在一定的情况下可以相互转换,比如:用队列实现栈,或者用栈实现队列。
2、想要熟悉栈和队列的话,那么二者的常用方法的使用以及实现一定要熟悉
比如:队列的常用方法有:
1)入队:使用offer/add都可以但是二者也有区别:
一些队列有大小限制,因此如果想在一个满的队列中加入一个新项,多出的项就会被拒绝。这时新的 offer 方法就可以起作用了。它不是对调用 add() 方法抛出一个 unchecked 异常,而只是得到由 offer() 返回的 false。
2)出队:pop/remove:
remove() 和 poll() 方法都是从队列中删除第一个元素。
remove()方法在失败的时候会抛出异常
poll() 方法在用空集合调用时不是抛出异常,只是返回 null。
3)查看队首元素:peek/element:
element() 和 peek() 用于在队列的头部查询元素。
在队列为空时, element() 抛出一个异常,而 peek() 返回 null。
栈的常用方法有:
1)入栈:push
//压栈操作(插入元素)(O(1))
public void push(long x){
stackArray[++top]=x;
}
2)出栈:pop
//出栈操作(删除元素)(O(1))
public long pop(){
return stackArray[top--];
}
3)访问栈顶元素:peek
//访问栈顶元素(O(1))
public long peek(){
return stackArray[top];
}
4)判断栈是否为空:isEmpty
//判断栈是否为空
public boolean isEmpty(){
return (top==-1);
}