文章目录
- 前言
- 1.队列(Queue)的概念
- 2.Queue的使用
- 3.队列的模拟实现
- 4.循环队列
- 5.双端队列
- 6.面试题
- [1. 用队列实现栈](https://leetcode.cn/problems/implement-stack-using-queues/description/)
- [2. 用栈实现队列](https://leetcode.cn/problems/implement-queue-using-stacks/description/)
前言
上一篇我们学习了栈(Stack) ,现在讲队列(Queue)。
1.队列(Queue)的概念
队列:只允许在一端进行插入数据操作,在另一端进行删除数据操作的特殊线性表,队列具有先进先出FIFO(First In First Out) 入队列:进行插入操作的一端称为队尾(Tail/Rear) 出队列:进行删除操作的一端称为队头(Head/Front)
2.Queue的使用
在Java中,Queue是个接口,底层是通过链表实现的。
public static void main(String[] args) {Queue<Integer> queue = new LinkedList<>();queue.offer(1);queue.offer(2);queue.offer(3);queue.offer(4);queue.offer(5); // 从队尾入队列System.out.println(queue.size());System.out.println(queue.peek()); // 获取队头元素queue.poll();System.out.println(queue.poll()); // 从队头出队列,并将删除的元素返回if(queue.isEmpty()){System.out.println("队列空");}else{System.out.println(queue.size());}}
3.队列的模拟实现
队列中既然可以存储元素,那底层肯定要有能够保存元素的空间,通过前面线性表的学习了解到常见的空间类型有两种:顺序结构 和 链式结构。思考下:队列的实现使用顺序结构还是链式结构好?
public class MyQueue {static class ListNode{public int val;public ListNode prev;public ListNode next;public ListNode(int val) {this.val = val;}}public ListNode first;public ListNode last;public int usedSize = 0;public void offer(int data){ListNode node = new ListNode(data);if (isEmpty()){first = last = node;}else {last.next = node;node.prev = last;last = node;}this.usedSize++;}public int poll(){if (isEmpty()){return -1;}int val = first.val;first = first.next;if (first!=null){first.prev = null;}this.usedSize--;return val;}public int peek(){if (isEmpty()){return -1;}return first.val;}public boolean isEmpty(){return usedSize == 0;}
}
4.循环队列
如何使用顺序表来模拟队列?
使用循环队列。
实际中我们有时还会使用一种队列叫循环队列。如操作系统课程讲解生产者消费者模型时可以就会使用循环队列。环形队列通常使用数组实现。
有下面三个问题需要先解决:
- 怎么判断数组已经满了?
- 怎么判断数组是空的?
- 如何使数组下标进行循环?
在这我们使用方案二进行操作。
设计循环队列
class MyCircularQueue {public int rear;public int front;public int[]elem;public MyCircularQueue(int k) {elem = new int[k+1];}public boolean enQueue(int value) {if (isFull()){return false;}elem[rear] = value;rear = (rear + 1) % elem.length;return true;}public boolean deQueue() {if (isEmpty()){return false;}front = (front + 1) % elem.length;return true;}public int Front() {if (isEmpty()){return -1;}return elem[front];}public int Rear() {if (isEmpty()){return -1;}int index = (rear == 0)? elem.length-1 : rear - 1;return elem[index];}public boolean isEmpty() {return rear == front;}public boolean isFull() {return (rear+1)%elem.length == front;}
}
5.双端队列
双端队列(deque)是指允许两端都可以进行入队和出队操作的队列,deque 是 “double ended queue” 的简称。
那就说明元素可以从队头出队和入队,也可以从队尾出队和入队。
Deque是一个接口,使用时必须创建LinkedList的对象。
在实际工程中,使用Deque接口是比较多的,栈和队列均可以使用该接口
Deque< Integer > stack = new ArrayDeque<>();//双端队列的线性实现
Deque< Integer > queue = new LinkedList<>();//双端队列的链式实现
6.面试题
1. 用队列实现栈
class MyStack {public Queue<Integer> queue1;public Queue<Integer> queue2;public MyStack() {queue1 = new LinkedList();queue2 = new LinkedList();}public void push(int x) {if (!queue1.isEmpty()){queue1.offer(x);}else if (!queue2.isEmpty()){queue2.offer(x);}else{queue1.offer(x);}}public int pop() {if (empty()){return -1;}if (!queue1.isEmpty()){int size = queue1.size();for (int i=0;i<size-1;i++){queue2.offer(queue1.poll());}return queue1.poll();}else{int size = queue2.size();for(int i = 0;i<size-1;i++){queue1.offer(queue2.poll());}return queue2.poll();}}public int top() {if (empty()){return -1;}if (!queue1.isEmpty()){int size = queue1.size();int val = 0;for (int i = 0; i< size;i++){val = queue1.poll();queue2.offer(val);}return val;}else{int size = queue2.size();int val = 0;for(int i = 0;i<size;i++){val = queue2.poll();queue1.offer(val);}return val;}}public boolean empty() {return queue1.isEmpty()&&queue2.isEmpty();}
}
2. 用栈实现队列
class MyQueue {public ArrayDeque<Integer> stack1;public ArrayDeque<Integer> stack2;public MyQueue() {stack1 = new ArrayDeque();stack2 = new ArrayDeque();}public void push(int x) {stack1.push(x); }public int pop() {if (empty()){return -1;}if (stack2.isEmpty()){while(!stack1.isEmpty()){stack2.push(stack1.pop());}}return stack2.pop();}public int peek() {if (empty()){return -1;}if (stack2.isEmpty()){while(!stack1.isEmpty()){stack2.push(stack1.pop());}}return stack2.peek();}public boolean empty() {return stack1.isEmpty()&&stack2.isEmpty();}
}
下一篇便要进入现阶段比较难的二叉树的部分,大家做好准备,开干!