代码随想录算法训练营第10天| | 栈和队列理论基础 | | 232.用栈实现队列 | | 225.用队列实现栈
栈和队列理论基础
Java中的栈
- 栈是Vector的一个子类,实现标准的后进先出的栈,这也意味着Stack的底层实现和Vector类似,扩容机制也一样
- Stack同Vector一样,在方法上添加了synchronized,达到线程安全的目的,但是这特别消耗资源,不推荐使用
Java中的队列
- Queue是个接口,设计了基础方法,具体实现代码取决于实现类
- Queue的常见底层实现为LinkList,底层链表实现
双向队列Deque(较为常用,同时具有栈和队列的功能)
- 继承Queue,且增加反向序列的方法
- 支持尾部插入,头部插入,尾部弹出,头部弹出等,参考网址
232.用栈实现队列
使用栈(只能使用几个基本操作)实现队列的下列操作:
push(x) – 将一个元素放入队列的尾部。
pop() – 从队列首部移除元素。
peek() – 返回队列首部的元素。
empty() – 返回队列是否为空。
个人思路:
- 因为栈的顺序是先进先出,所以一放一出顺序就正常了
- 这里我们只要设计两个栈,一个用于存入,另一个用于弹出,只有当弹出栈为空,才将存入栈弹到弹出栈保存,放在顺序混乱
class MyQueue {
Stack<Integer> stackIn;
Stack<Integer> stackOut;
public MyQueue() {
stackIn = new Stack<>();
stackOut = new Stack<>();
}
public void push(int x) {
stackIn.push(x);
if (stackOut.empty()) {
while (!stackIn.empty()) {
stackOut.push(stackIn.pop());
}
}
}
public int pop() {
if (stackOut.empty()) {
while (!stackIn.empty()) {
stackOut.push(stackIn.pop());
}
}
return stackOut.pop();
}
public int peek() {
if (stackOut.empty()) {
while (!stackIn.empty()) {
stackOut.push(stackIn.pop());
}
}
return stackOut.peek();
}
public boolean empty() {
return stackOut.empty() && stackIn.empty();
}
}
题解解析:(和上述办法差不多)
- 需要一个输入栈和一个输出栈
- pop操作时,输出栈如果为空,就要把进栈数据全导过来(注意是全部导入)
- 如果两个栈都为null,则队列为null
- 注意相近的代码要抽象出来,不要大量的复制粘贴,很容易出问题,上述代码就存在这个问题
//改进代码
class MyQueue {
Stack<Integer> stackIn;
Stack<Integer> stackOut;
public MyQueue() {
stackIn = new Stack<>();
stackOut = new Stack<>();
}
public void push(int x) {
stackIn.push(x);
}
public int pop() {
dumpstackIn();
return stackOut.pop();
}
public int peek() {
dumpstackIn();
return stackOut.peek();
}
public boolean empty() {
return stackOut.empty() && stackIn.empty();
}
//注意此处是私有方法,不暴露给外部
private void dumpstackIn() {
if (!stackOut.isEmpty()) return;
while (!stackIn.isEmpty()) {
stackOut.push(stackIn.pop());
}
}
}
225.用队列实现栈
使用队列实现栈的下列操作:
- push(x) – 元素 x 入栈
- pop() – 移除栈顶元素
- top() – 获取栈顶元素
- empty() – 返回栈是否为空
个人思路:
- 法一:使用两个队列
- 一个队列用于输入元素,另一个队列在获取元素时作为临时存放站
- 每次获取元素时,都要将数据从一个队列全部存放到另一个队列,然后输出最后一个或弹出最后一个
class MyStack {
Queue<Integer> queue1;
Queue<Integer> queue2;
public MyStack() {
queue1 = new LinkedList<>();
queue2 = new LinkedList<>();
}
public void push(int x) {
queue1.add(x);
}
public int pop() {
if (queue1.isEmpty())
return -1;
while (queue1.size() != 1) {
queue2.add(queue1.poll());
}
Integer poll = queue1.poll();
queue1 = queue2;
queue2 = new PriorityQueue<>();
return poll;
}
public int top() {
Integer poll = pop();
queue1.add(poll);
return poll;
}
public boolean empty() {
return queue1.isEmpty();
}
}
- 法二:使用一个队列
- 当需要弹出或获取栈顶元素时,只需要一边弹出一边存入即可,循环n-1次即可
class MyStack {
Queue<Integer> queue;
public MyStack() {
queue = new LinkedList<>();
}
public void push(int x) {
queue.add(x);
}
public int pop() {
if (queue.isEmpty())
return -1;
for (int i = 0; i < queue.size() - 1; i++) {
queue.add(queue.poll());
}
return queue.poll();
}
public int top() {
Integer poll = pop();
queue.add(poll);
return poll;
}
public boolean empty() {
return queue.isEmpty();
}
}