目录
栈与队列理论基础
栈与队列:栈为先进后出,队列为先进先出的结构。
Queue以及Deque;平常在写leetcode经常用LinkedList向上转型Deque作为栈或者队列使用。
private static void usingAsQueue() {
Deque<Integer> queue=new ArrayDeque<>();
System.out.println("队列为空:"+queue.isEmpty()); //判断队列是否为空
queue.addLast(12); //添加元素
System.out.println(queue.peekFirst()); //获取队列首部元素
System.out.println(queue.pollFirst()); //获取并移除栈顶元素
}
private static void usingAsStack() {
//作为栈使用
Deque<Integer> stack=new LinkedList<>();
System.out.println("栈为空:"+stack.isEmpty()); //判断栈是否为空
stack.addFirst(12);//添加元素
System.out.println(stack.peekFirst()); //获取栈顶元素
System.out.println(stack.pollFirst()); //获取并移除栈顶元素
}
232 用栈实现队列
看到题目的第一想法:对栈与队列了解较少,看到后完全是没有思路的状态。
看完代码随想录之后的想法:按部就班的处理即可,先是定义两个栈,入栈stackIn与出栈stackOut,而后对队列进行初始化操作;
- 向队列中添加元素,只需要向入栈中push即可
- 队列弹出元素较为复杂,因为队列是先进先出的数据结构,而栈是先进后出的,故弹出时,先判断stackOut是否是空的:如果是空的,而若此时stackIn不为空,就将入栈的所有元素,依次弹出并放入出栈中。而后直接在出栈中弹出元素即可,这就用两个栈实现了队列的pop功能。
- 获取队列的顶部元素:直接复用pop方法即可,唯一不同是,peek不需要弹出,因此在调用this.pop()之后,再将此元素放入stackOut即可;
- 队列是否为空:两个栈有一个不为空时队列不为空,否则为空。判断队列是否为空的方法为:stack.isEmpty().
代码实现:
class MyQueue {
//stack的初始化与定义??如何处理
//定义一个入栈和一个出栈
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() {
//如果stackout为空,就将stackin中的所有元素放入stackout中
//若不为空,直接弹出元素
//isEmpty()方法
if (stackOut.isEmpty()) {
while (!stackIn.isEmpty()) {
stackOut.push(stackIn.pop());
}
}
return stackOut.pop();
}
public int peek() {
//复用pop方法
//int result = stackOut.pop();
int result = this.pop();
stackOut.push(result);
return result;
}
public boolean empty() {
//至少一个不为空时,队列不为空
if (!stackIn.isEmpty() || !stackOut.isEmpty()){
return false;
}
return true;
}
}
/**
* Your MyQueue object will be instantiated and called as such:
* MyQueue obj = new MyQueue();
* obj.push(x);
* int param_2 = obj.pop();
* int param_3 = obj.peek();
* boolean param_4 = obj.empty();
*/
实现过程中遇到哪些困难:
- 不会定义栈,不会初始化队列,不了解栈的push,pop,peek,isEmpty等方法!
- this可以调用当前类的其他方法等
4225 用队列实现栈
看到题目的第一想法:没有思路,不清楚如何用队列实现栈
看完代码随想录之后的想法:卡哥提供的代码时使用队列deque,而后对栈初始化:
- 添加元素使用的是addLast方法;
- 栈的弹出元素操作:获取队列的长度,而后队列减一,即将队列中前size-1个元素全部在加到队列的后方。在完成之后移除队列的第一个元素即可,即实现了栈的pop功能
- 获取栈顶元素,arrayDeque.getLast()获取队列最后一个元素即相当于栈顶元素;
- 判断栈是否为空,直接判断队列是否为空即可,arrayDeque.isEmpty()
代码实现:(使用一个deque实现)
class MyStack {
//使用一个队列即可实现栈
//deque双端队列(两侧都可以增删元素),queue单端队列(先进先出)
Deque<Integer> que;
public MyStack() {
que = new ArrayDeque<>();
}
public void push(int x) {
que.addLast(x);
}
public int pop() {
int size = que.size();
size--;
//下面应为 > 0而非 >= 0
while (size-- > 0) {
que.addLast(que.peekFirst());
que.pollFirst();
}
int res = que.pollFirst();
return res;
}
public int top() {
//java中队列有back吗?
return que.getLast();
}
public boolean empty() {
return que.isEmpty();
}
}
/**
* 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();
* boolean param_4 = obj.empty();
*/
使用一个queue实现:
class MyStack {
Queue<Integer> queue;
public MyStack() {
queue = new LinkedList<>();
}
//每 offer 一个数(A)进来,都重新排列,把这个数(A)放到队列的队首
public void push(int x) {
queue.offer(x);
int size = queue.size();
//移动除了 A 的其它数
while (size-- > 1)
queue.offer(queue.poll());
}
public int pop() {
return queue.poll();
}
public int top() {
return queue.peek();
}
public boolean empty() {
return queue.isEmpty();
}
}
使用两个queue实现:
class MyStack {
Queue<Integer> queue1; // 和栈中保持一样元素的队列,此处保持一致即出栈顺序一致
Queue<Integer> queue2; // 辅助队列
/** Initialize your data structure here. */
public MyStack() {
queue1 = new LinkedList<>();
queue2 = new LinkedList<>();
}
/** Push element x onto stack. */
public void push(int x) {
queue2.offer(x); // 先放在辅助队列中
while (!queue1.isEmpty()){
queue2.offer(queue1.poll());
}
Queue<Integer> queueTemp;
queueTemp = queue1;
queue1 = queue2;
queue2 = queueTemp; // 最后交换queue1和queue2,将元素都放到queue1中
}
/** Removes the element on top of the stack and returns that element. */
public int pop() {
return queue1.poll(); // 因为queue1中的元素和栈中的保持一致,所以这个和下面两个的操作只看queue1即可
}
/** Get the top element. */
public int top() {
return queue1.peek();
}
/** Returns whether the stack is empty. */
public boolean empty() {
return queue1.isEmpty();
}
}
用两个deque实现栈:
class MyStack {
// Deque 接口继承了 Queue 接口
// 所以 Queue 中的 add、poll、peek等效于 Deque 中的 addLast、pollFirst、peekFirst
Deque<Integer> que1; // 和栈中保持一样元素的队列,此处保持一致为入栈顺序一致
Deque<Integer> que2; // 辅助队列
/** Initialize your data structure here. */
public MyStack() {
que1 = new ArrayDeque<>();
que2 = new ArrayDeque<>();
}
/** Push element x onto stack. */
public void push(int x) {
que1.addLast(x);
}
/** Removes the element on top of the stack and returns that element. */
public int pop() {
int size = que1.size();
size--;
// 将 que1 导入 que2 ,但留下最后一个值
while (size-- > 0) {
que2.addLast(que1.peekFirst());
que1.pollFirst();
}
int res = que1.pollFirst();
// 将 que2 对象的引用赋给了 que1 ,此时 que1,que2 指向同一个队列
que1 = que2;
// 如果直接操作 que2,que1 也会受到影响,所以为 que2 分配一个新的空间
que2 = new ArrayDeque<>();
return res;
}
/** Get the top element. */
public int top() {
return que1.peekLast();
}
/** Returns whether the stack is empty. */
public boolean empty() {
return que1.isEmpty();
}
}
实现过程中遇到哪些困难:
- 队列的相关方法不了解,需要多熟悉,比如ArrayDeque的addLast,peekFirst,pollFirst,getLast,isEmpty等
今日收获,记录一下自己的学习时长
- 算法处理约3h,博客编写约1.5h
- 熟悉了队列与栈相互实现的操作,与其基本用法,还要多加了解~
- 贵在坚持,加油!