前言:本文将简单介绍一下如何使用栈(stack)来模拟实现队列(queue)以及如何使用队列来模拟实现栈
栈的特性是后进先出,就像一个乒乓球筒,最后放进去的乒乓球一定是最先被倒出球筒的.
队列特性就是先进先出,每次pop或者peek操作都是从队列的顶部出队列
一,使用栈模拟实现队列
(一)如何实现?使用双栈法
要想使得栈中的元素每次poll能得到最先进的元素,可以使用两个栈,一个是输入栈stack1 ,另外一个是输出栈stack2
push的元素全部进入输入栈stack1 ,当进行出栈操作的时候,为了拿到我们最先放的元素,stack1中的元素全部出栈,然后依次压入stack2输出栈中,此时就会发现在stack1中原先位置处于最底部的元素就被调换到了stack2的栈顶位置,此时直接把stack.poll()就能拿到对应元素了
但是需要注意,不是每次进行出栈操作时,我们都需要进行一次上面的操作(把stack1的元素出栈,压入stack2) 而是在poll或者peek之前先进行一次stack2的判空操作, 如果stack2为空, 说明之前stack2中的元素被出完了,需要从stack1中再搬过来一点. 如果!stack2.isEmpty() 则直接从stack2的栈顶拿就好了
下面是一个简单的模拟实现

(二)代码参考
这是一个通过java代码实现的双栈模拟实现队列代码:
java
import java.util.Stack;
public class MyQueue {
private Stack<Integer> stackIn;
private Stack<Integer> stackOut;
public MyQueue() {
stackIn = new Stack<>();
stackOut = new Stack<>();
}
public void push(int num) {
stackIn.push(num);
}
public int pop() {
// 先确保输出栈有东西
dumpStack();
if (stackOut.isEmpty()) throw new RuntimeException("Queue is empty");
return stackOut.pop();
}
public int peek() {
dumpStack();
if (stackOut.isEmpty()) throw new RuntimeException("Queue is empty");
return stackOut.peek();
}
// 统一的"搬栈"逻辑
private void dumpStack() {
// 关键:只有输出栈为空时才搬运,否则会打乱顺序
if (stackOut.isEmpty()) {
while (!stackIn.isEmpty()) {
stackOut.push(stackIn.pop());
}
}
}
public int getSize() {
return stackIn.size() + stackOut.size();
}
public boolean isEmpty() {
return stackIn.isEmpty() && stackOut.isEmpty();
}
public static void main(String[] args) {
MyQueue myQueue = new MyQueue();
int[] nums = {1, 2, 3, 4, 5};
for (int x : nums) myQueue.push(x);
System.out.println(myQueue.pop()); // 1
System.out.println(myQueue.getSize()); // 4
}
}
二,使用队列模拟实现栈
(一)如何实现?
为了让队列表现得像栈,我们只需要在queue每次push新元素时,把前面已经存在的元素依次出队,再重新入队排到新元素的后面 。这样,新加入的元素就永远被顶在了队列的最前端。

栈的每次push操作之后,都把前面n-1个元素移动到队尾,这是核心思想.那么那么是否可以在我们每次需要查看栈顶元素的时候来在进行上面的队列翻转操作呢?
- 如果在pop的时候才进行翻转,则每次我们需要查看栈顶元素peek,或者出栈pop时都需要进行一次翻转操作,这个时间复杂度为O(n),但是push的时间复杂度降低为O(1),
- 但是若是按照push时进行翻转操作,则只有push时的时间复杂度为O(n),查看栈顶,出栈的时间复杂度则为O(1).在频繁的操作栈中元素,查看栈顶元素的时候性能较高
(二)代码实现
java
import java.util.LinkedList;
import java.util.Queue;
public class MyStack {
private Queue<Integer> queue;
// 初始化队列
public MyStack() {
queue = new LinkedList<>();
}
// 入栈操作
public void push(int x) {
// 1. 先记录当前队列里的元素个数
int n = queue.size();
// 2. 将新元素加入队尾
queue.offer(x);
// 3. 将新元素之前的所有元素依次出队,并重新加入队尾
for (int i = 0; i < n; i++) {
queue.offer(queue.poll());
}
}
// 出栈操作
public int pop() {
// 此时队头元素就是最后加进来的元素,直接出队即可
return queue.poll();
}
// 获取栈顶元素
public int top() {
return queue.peek();
}
// 判断栈是否为空
public boolean empty() {
return queue.isEmpty();
}
}
有关栈和队列的互相模拟实现就简单到这里了,如有纰漏还请指出~~