概念
队列也是一种线性结构,相比数组,队列对应的操作是数组的子集,只能从一端(队尾)添加元素,只能从另一端(队首)取出元素.
特点
数组队列
实现
public interface Queue<E> {/*** 入队操作** 时间复杂度 O(1) 均摊 ArrayQueue 和 LoopQueue同* @param e 元素*/void enqueue(E e);/*** 出队操作** 时间复杂度 O(n) ArrayQueue复杂度为O(n) LoopQueue复杂度O(1) 均摊* 出队拿出数组中第一个元素后,剩下的元素都要前移* @return 元素*/E dequeue();/*** 查看队列队首的元素** 时间复杂度 O(1) ArrayQueue 和 LoopQueue同* @return 元素*/E getFront();/*** 获取队列的数量** 时间复杂度 O(1) ArrayQueue 和 LoopQueue同* @return size*/int getSize();/*** 判断队列是否为空** 时间复杂度 O(1) ArrayQueue 和 LoopQueue同* @return true为空, false反之*/boolean isEmpty();}
注意:这里的Array类是前面动态数组实现的Array类,点击跳转:动态数组
public class ArrayQueue<E> implements Queue<E> {Array<E> array;public ArrayQueue(int capacity){array = new Array<>(capacity);}public ArrayQueue(){array = new Array<>();}@Overridepublic void enqueue(E e) {//向数组的末尾添加元素array.addLast(e);}@Overridepublic E dequeue() {//取出第一个元素return array.removeFirst();}@Overridepublic E getFront() {return array.getFirst();}@Overridepublic int getSize() {return array.getSize();}@Overridepublic boolean isEmpty() {return array.isEmpty();}public int getCapacity(){return array.getCapacity();}@Overridepublic String toString() {StringBuilder builder = new StringBuilder();builder.append("Queue: ");builder.append("front [");for (int i = 0; i < array.getSize(); i++) {builder.append(array.get(i));if (i != array.getSize() - 1) {builder.append(",");}}builder.append("] tail");return builder.toString();}public static void main(String[] args) {ArrayQueue<Integer> arrayQueue = new ArrayQueue<>();for (int i = 0; i < 10; i++) {//向队列中添加元素arrayQueue.enqueue(i);System.out.println(arrayQueue);if (i % 3 == 2){arrayQueue.dequeue();System.out.println(arrayQueue);}}}}
局限
队列的出队操作时间复杂度为O(n),因为出队是把数组的第一个元素删除,那么剩余的其他元素必须全部前移.
循环队列
队首front == 队尾tail 时队列为空
(tail + 1) % 队列长度capacity== front时 队列满
实现
public class LoopQueue<E> implements Queue<E> {private E[] data;private int front, tail;private int size;@SuppressWarnings("unchecked")public LoopQueue(int capacity) {data = (E[]) new Object[capacity + 1];front = 0;tail = 0;size = 0;}public int getCapacity() {return data.length - 1;}public LoopQueue() {this(10);}@Overridepublic void enqueue(E e) {if ((tail + 1) % data.length == front) {resize(getCapacity() * 2);}data[tail] = e;tail = (tail + 1) % data.length;size++;}@SuppressWarnings("unchecked")private void resize(int newCapacity) {E[] newData = (E[]) new Object[newCapacity + 1];for (int i = 0; i < size; i++) {//新数组第一个元素对应的data是front,第二个元素是front+1,第三个是front+2,依次类推//循环队列可能会产生数组越界newData[i] = data[(i + front) % data.length];}data = newData;front = 0;tail = size;}@Overridepublic E dequeue() {if (isEmpty()) {throw new IllegalArgumentException("Cannot dequeue from an empty queue");}E ret = data[front];data[front] = null;front = (front + 1) % data.length;size--;//缩容if (size == getCapacity() / 4 && getCapacity() / 2 != 0) {resize(getCapacity() / 2);}return ret;}@Overridepublic E getFront() {if (isEmpty()) {throw new IllegalArgumentException("Cannot dequeue from an empty queue");}return data[front];}@Overridepublic int getSize() {return size;}@Overridepublic boolean isEmpty() {return front == tail;}@Overridepublic String toString() {StringBuilder builder = new StringBuilder();builder.append(String.format("Queue: size = %d,capacity = %d\n", size, data.length));builder.append("fount [");for (int i = 0; i != tail; i = (i + 1) % data.length) {builder.append(data[i]);if (i != size - 1) {builder.append(",");}}builder.append("] tail");return builder.toString();}}
数组队列和循环队列比较
public class TestQueue {public static void main(String[] args) {int opCount = 100000;System.out.println("数组队列ArrayQueue耗时: " + testQueue(new ArrayQueue<>(), opCount) + "s");System.out.println("循环队列LoopQueue耗时: " + testQueue(new LoopQueue<>(), opCount) + "s");}private static double testQueue(Queue<Integer> q, int opCount) {long startTime = System.nanoTime();SecureRandom random = new SecureRandom();for (int i = 0; i < opCount; i++) {//入队操作q.enqueue(random.nextInt(Integer.MAX_VALUE));}for (int i = 0; i < opCount; i++) {//出队操作q.dequeue();}long endTime = System.nanoTime();return (endTime - startTime)/1000000000.0;}}
双端队列
实现
public class Deque<E> {private E[] data;private int front, tail;private int size;@SuppressWarnings("unchecked")public Deque(int capacity) {data = (E[]) new Object[capacity];front = 0;tail = 0;size = 0;}public Deque() {this(10);}public int getCapacity() {return data.length;}public boolean isEmpty() {return size == 0;}public int getSize() {return size;}/*** 在队尾添加元素** @param e 元素*/public void addLast(E e) {// addLast 的逻辑和我们之前实现的队列中的 enqueue 的逻辑是一样的if (size == getCapacity()) {resize(getCapacity() * 2);}data[tail] = e;tail = (tail + 1) % data.length;size++;}/*** 在队首添加元素** @param e 元素*/public void addFront(E e) {if (size == getCapacity()) {resize(getCapacity() * 2);}// 我们首先需要确定添加新元素的索引位置// 这个位置是 front - 1 的地方// 但是要注意,如果 front == 0,新的位置是 data.length - 1 的位置front = front == 0 ? data.length - 1 : front - 1;data[front] = e;size++;}/*** 删除队首元素** @return 返回被删除的元素*/public E removeFront() {// removeFront 的逻辑和我们之前实现的队列中的 dequeue 的逻辑是一样的if (isEmpty()) {throw new IllegalArgumentException("Cannot dequeue from an empty queue.");}E ret = data[front];data[front] = null;front = (front + 1) % data.length;size--;if (getSize() == getCapacity() / 4 && getCapacity() / 2 != 0) {resize(getCapacity() / 2);}return ret;}/*** 删除队尾元素** @return 被删除的元素*/public E removeLast() {if (isEmpty()) {throw new IllegalArgumentException("Cannot dequeue from an empty queue.");}// 计算删除掉队尾元素以后,新的 tail 位置tail = tail == 0 ? data.length - 1 : tail - 1;E ret = data[tail];data[tail] = null;size--;if (getSize() == getCapacity() / 4 && getCapacity() / 2 != 0) {resize(getCapacity() / 2);}return ret;}/*** 获取队首元素** @return 元素*/public E getFront() {if (isEmpty()) {throw new IllegalArgumentException("Queue is empty.");}return data[front];}/*** 获取队尾元素** @return 队尾元素*/public E getLast() {if (isEmpty()) {throw new IllegalArgumentException("Queue is empty.");}// 因为 tail 指向的是队尾元素的下一个位置,我们需要计算一下真正队尾元素的索引int index = tail == 0 ? data.length - 1 : tail - 1;return data[index];}/*** 缩容和扩容** @param newCapacity 新的队列长度*/@SuppressWarnings("unchecked")private void resize(int newCapacity) {E[] newData = (E[]) new Object[newCapacity];for (int i = 0; i < size; i++) {newData[i] = data[(i + front) % data.length];}data = newData;front = 0;tail = size;}@Overridepublic String toString() {StringBuilder res = new StringBuilder();res.append(String.format("Queue: size = %d , capacity = %d\n", getSize(), getCapacity()));res.append("front [");for (int i = 0; i < size; i++) {res.append(data[(i + front) % data.length]);if (i != size - 1) {res.append(", ");}}res.append("] tail");return res.toString();}public static void main(String[] args) {// 在下面的双端队列的测试中,偶数从队尾加入;奇数从队首加入Deque<Integer> dq = new Deque<>();for (int i = 0; i < 16; i++) {if (i % 2 == 0) {dq.addLast(i);} else {dq.addFront(i);}System.out.println(dq);}// 之后,我们依次从队首和队尾轮流删除元素System.out.println();for (int i = 0; !dq.isEmpty(); i++) {if (i % 2 == 0) {dq.removeFront();} else {dq.removeLast();}System.out.println(dq);}}}
用队列实现栈(leetcode225)
要求
你仅使用两个队列实现一个后入先出(LIFO)的栈,并支持普通队列的全部四种操作(push、top、pop 和 empty)
实现 MyStack 类:
- void push(int x) 将元素 x 压入栈顶。
- int pop() 移除并返回栈顶元素。
- int top() 返回栈顶元素。
boolean empty() 如果栈是空的,返回 true ;否则,返回 false 。
Java实现
```java public class MyStack {
Queue
queue; public MyStack() {
queue = new LinkedList<>();
}
/**
Push element x onto stack. */ public void push(int x) { //队列长度 int size = queue.size(); queue.offer(x); for (int i = 0; i < size; i++) {
//将队列的第一个元素删除并再次放入队列queue.offer(queue.poll());
} }
/**
Removes the element on top of the stack and returns that element. */ public int pop() { if (queue.size() == 0) {
throw new IllegalArgumentException("queue is empty");
} return queue.poll(); }
/**
Get the top element. */ public int top() { if (queue.size() == 0) {
throw new IllegalArgumentException("queue is empty");
} return queue.peek(); }
/**
- Returns whether the stack is empty. */ public boolean empty() { return queue.isEmpty(); }
}
<a name="gR5G8"></a>### go实现```gotype MyStack struct {queue []int}/** Initialize your data structure here. */func Constructor() (s MyStack) {return}/** Push element x onto stack. */func (s *MyStack) Push(x int) {n := len(s.queue)s.queue = append(s.queue, x)for ; n > 0; n-- {s.queue = append(s.queue, s.queue[0])s.queue = s.queue[1:]}}/** Removes the element on top of the stack and returns that element. */func (s *MyStack) Pop() int {v := s.queue[0]s.queue = s.queue[1:]return v}/** Get the top element. */func (s *MyStack) Top() int {return s.queue[0]}/** Returns whether the stack is empty. */func (s *MyStack) Empty() bool {return len(s.queue) == 0}
用栈实现队列(leetcode232)
要求
请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作(push、pop、peek、empty)
- void push(int x) 将元素 x 推到队列的末尾
- int pop() 从队列的开头移除并返回元素
- int peek() 返回队列开头的元素
boolean empty() 如果队列为空,返回 true ;否则,返回 false
Java实现
```java public class MyQueue { Deque
inStack; Deque outStack; /**
Initialize your data structure here. */ public MyQueue() { inStack = new LinkedList<>(); outStack = new LinkedList<>(); }
/**
Push element x to the back of queue. */ public void push(int x) { inStack.push(x); }
/**
Removes the element from in front of queue and returns that element. */ public int pop() { //当输出栈为空时 if (outStack.isEmpty()) {
//执行将输入栈中元素依次弹出并放入输出栈in2out();
} return outStack.pop(); }
/**
Get the front element. */ public int peek() { if (outStack.isEmpty()) {
in2out();
} return outStack.peek(); }
/**
Returns whether the queue is empty. */ public boolean empty() { return inStack.isEmpty() && outStack.isEmpty(); }
private void in2out() { //当输入栈不为空时,循环将输入栈得元素放入输出栈 while (!inStack.isEmpty()) {
outStack.push(inStack.pop());
} } }
<a name="2LqTh"></a>### go实现```gotype MyQueue struct {inStack, outStack []int}func Constructor1() (q MyQueue) {return}func (q *MyQueue) Push(x int) {q.inStack = append(q.inStack, x)}func (q *MyQueue) in2out() {for len(q.inStack) > 0 {q.outStack = append(q.outStack, q.inStack[len(q.inStack)-1])q.inStack = q.inStack[:len(q.inStack)-1]}}func (q *MyQueue) Pop() int {if len(q.outStack) == 0 {q.in2out()}x := q.outStack[len(q.outStack)-1]q.outStack = q.outStack[:len(q.outStack)-1]return x}func (q *MyQueue) Peek() int {if len(q.outStack) == 0 {q.in2out()}return q.outStack[len(q.outStack)-1]}func (q *MyQueue) Empty() bool {return len(q.inStack) == 0 && len(q.outStack) == 0}
