队列、循环队列、用队列模拟栈、用栈模拟队列
- 1.队列
- 1.1 什么是队列
- 1.2 创建队列
- 1.3 队列是否为空和获取队头元素 empty()+peek()
- 1.4 入队offer()
- 1.5 出队(头删)poll()
- 2. 循环队列
- 2.1 创建循环队列
- 2.2 判断是否为空isEmpty()和满isFull()
- 2.3 入队enQueue()
- 2.4 出队 deQueue()
- 2.5 得到队头元素不删除 Front()
- 2.6 得到队尾元素不删除 Rear()
- 3.用队列模拟栈
- 3.1 实例化两个队列
- 3.2 判断栈是否为空
- 3.1 入栈push()
- 3.2 出栈pop()
- 3.3 获取栈顶元素top()
- 4.用栈模拟队列
- 4.1 实例化两个栈
- 4.2 入队push()
- 4.3 出队pop()
- 4.4 获取队顶元素peek()+队列是否为空empty()
1.队列
1.1 什么是队列
只允许在一端进行插入数据操作,在另一端进行删除数据操作得特殊线性表,队列是先进先出,入队:进行插入操作得一端称为队尾(rear),出队:进行删除操作的一端称为队头(front)。队列Queue是个接口,底层通过链表实现的。
- boolean offer(E e) – 入队列
- E poll() – 出队列
- peek() – 获取队头元素
- int size() – 获取队列中有效元素个数
- boolean isEmpty() – 检测队列是否为空
注意:Queue是个接口,在实例化时必须实例化LinkedList的对象,因为LinkedList实现了Queue接口。
1.2 创建队列
public class MyQueue {static class ListNode {public int val;public ListNode prev;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode head; // 队头public ListNode last; // 队尾
}
1.3 队列是否为空和获取队头元素 empty()+peek()
public boolean empty() {return head == null;}public int peek() {if (head == null) {return -1;}return head.val;}
1.4 入队offer()
入队相当于链表的尾插法,入队元素node,然后队列为空,直接把头尾节点指向node,不为空:从队尾入队操作,last的后节点指向node,node的前节点指向last,last再指向node。
public void offer(int val) {ListNode node = new ListNode(val);if (head == null) {head = last = node;}else {last.next = node;node.prev = last;last = node;}}
1.5 出队(头删)poll()
给个临时变量val,当只有一个节点时:val指向head.val,出队完head指向null,返回val。不止一个节点:val指向head.val,head指向head的后节点,head的前驱节点指向null,返回val。
public int poll() {if(head == null) {return -1;}//只有一个节点int val = -1;if (head.next == null) {val = head.val;head = null;return val;}val = head.val;head = head.next;head.prev = null;return val;}
2. 循环队列
假如队列的大小为8,当7走到下一个下标0的时候,下标+1实现不了,所有在循环队列当中,实现数组下标循环:队头:front = (front + 1) % elem.length,队尾:rear = (rear + 1) % elem.length,区分队列空和满:当队头front和队尾rear相遇时为空。当队尾rear的下个为队头front为满。
2.1 创建循环队列
class MyCircularQueue {// 循环队列public int[] elem;public int front;public int rear;public MyCircularQueue(int k) {elem = new int[k+1];}
}
2.2 判断是否为空isEmpty()和满isFull()
public boolean isEmpty() {return front == rear;}public boolean isFull() {return (rear+1) % elem.length == front;}
2.3 入队enQueue()
public boolean enQueue(int value) {if (isFull()) {return false;}else {elem[rear] = value;rear = (rear + 1) % elem.length;return true;}}
2.4 出队 deQueue()
public boolean deQueue() {if(isEmpty()) {return false;}else {// 得到数组下标最后再完后的下标 如果最大是8,后面跳转到0front = (front + 1) % elem.length;return true;}}
2.5 得到队头元素不删除 Front()
public int Front() {if (isEmpty()) {return -1;}return elem[front];}
2.6 得到队尾元素不删除 Rear()
public int Rear() {if (isEmpty()) {return -1;}int index = (rear == 0) ? elem.length-1 : rear-1;return elem[index];}
3.用队列模拟栈
在这里用到两个先进先出的队列来实现栈。
思路:
- 1.当两个队列都是空的时候,放到第一个队列
- 2.再次入栈的时候,放到不为空的队列
- 3.出栈的时候,出不为空的队列 出size-1个元素,剩下的元素就是要出栈的元素
3.1 实例化两个队列
class MyStack{private Queue<Integer> qu1;private Queue<Integer> qu2;public MyStack() {qu1 = new LinkedList<>();qu2 = new LinkedList<>();}
}
3.2 判断栈是否为空
判断栈是否为空我们直接返回两个队列是否为空。
public boolean empty() {return qu1.isEmpty() && qu2.isEmpty();}
3.1 入栈push()
当两个队列都是空的时候,放到第一个队列,再次入栈的时候,放到不为空的队列
public void push(int x) {if (empty()) {qu1.offer(x);return;}if (!qu1.isEmpty()) {qu1.offer(x);}else {qu2.offer(x);}}
3.2 出栈pop()
找到不为空的队列 出size-1个元素 剩下的元素就是出栈的元素,每弹出一个size都在变小一次,
public int pop() {if (empty()) {return -1;}// 找到不为空的队列 出size-1个元素 剩下的元素就是出栈的元素if (!qu1.isEmpty()) {int size = qu1.size();for (int i = 0; i < size-1; i++) {qu2.offer(qu1.poll());}return qu1.poll();}else {// 没弹出一个size都在变小一次int size = qu2.size();for (int i = 0; i < size-1; i++) {qu1.offer(qu2.poll());}return qu2.poll();}}
3.3 获取栈顶元素top()
和出栈一样,给一个临时变量tmp,用tmp接收队列的最后一个元素。
public int top() {if (empty()) {return -1;}if (!qu1.isEmpty()) {int size = qu1.size();int tmp = -1;for (int i = 0; i < size; i++) {tmp = qu1.poll();qu2.offer(tmp);}return tmp;}else {// 没弹出一个size都在变小一次int size = qu2.size();int tmp = -1;for (int i = 0; i < size; i++) {tmp = qu2.poll();qu1.offer(tmp);}return tmp;}}
4.用栈模拟队列
用栈模拟实现队列也需要用到两个栈,思路:
- 1.入队:把数据放到第一个栈中
- 2.出队:把第一个栈的全部元素放进第二栈当中,出st2这个栈当中的栈顶元素即可,如果st2为空,把st1里面所有的元素全部放到st2
- 3.当两个栈为空 说明模拟的栈队列为空
4.1 实例化两个栈
class MyQueue {private Stack<Integer> st1;private Stack<Integer> st2;public MyQueue() {st1 = new Stack<>();st2 = new Stack<>();}
}
4.2 入队push()
入栈直接全部放进第一个栈中
public void push(int x) {st1.push(x);}
4.3 出队pop()
把第一个栈的全部元素放进第二栈当中,出st2这个栈当中的栈顶元素即可,如果st2为空,把st1里面所有的元素全部放到st2
public int pop() {if(empty()) {return -1;}if(st2.empty()) {while(!st1.empty()) {st2.push(st1.pop());}}return st2.pop();}
4.4 获取队顶元素peek()+队列是否为空empty()
和出队一样,peek第二个栈的栈顶元素即可
public int peek() {if(empty()) {return -1;}if(st2.empty()) {while(!st1.empty()) {st2.push(st1.pop());}}return st2.peek();}public boolean empty() {return st1.empty() && st2.empty();}