1、队列
栈是一种先进后出线性数据结构,数据的插入和删除只能在一端操作。
队列是一种先进先出线性数据结构,队尾一端插入数据,队头一端删除数据。
2、单向队列的实现:
与基于数组的栈不同的是,基于数组实现的队列在出队操作时,相当于删除数组下标为 0 的数据,要搬移整个队列中的数据。
/**
* description: 基于数组实现队列
* date: 2019/8/21
* author: wp
*/
public class MyQueue {
/**
* 容器
*/
private Object[] elementData;
/**
* 队列的默认大小
*/
private static final int DEFAULT_SIZE = 10;
/**
* 队列中元素个数
*/
protected int elementCount;
/**
* 默认构造器
*/
public MyQueue() {
this(DEFAULT_SIZE);
}
/**
* 指定队列的容量构造器
*/
public MyQueue(int size) {
if (size < 0) {
throw new RuntimeException();
}
elementData = new Object[size];
}
/**
* 入队操作
* 将指定的元素插入此队列,(如果违反容量限制抛出IllegalStateException)
*
* @param obj
* @return
*/
public synchronized boolean add(Object obj) {
if (isFull()) {
//栈满了,需要扩容
throw new IllegalStateException();
}
elementData[elementCount] = obj;
elementCount++;
return true;
}
/**
* 入队操作
* 将指定的元素插入此队列,(如果违反容量限制不抛异常)
*
* @param obj
* @return
*/
public synchronized boolean offer(Object obj) {
if (isFull()) {
//栈满了,需要扩容
Object[] temp = elementData;
elementData = new Object[elementData.length * 2];
System.arraycopy(temp, 0, elementData, 0, temp.length);
}
elementData[elementCount] = obj;
elementCount++;
return true;
}
/**
* 出队操作
* 获取但不移除, 如果此队列为空,则返回 null
*
* @return
*/
public Object peek() {
if (!isEmpty()) {
return elementData[0];
}
return null;
}
/**
* 出队操作
* 获取但不移除, 如果此队列为空,则返回 null,如果此队列为空,则将抛出NoSuchElementException异常
*
* @return
*/
public synchronized Object element() {
if (isEmpty()) {
throw new NoSuchElementException();
}
return elementData[0];
}
/**
* 出队操作
* 获取并移除, 如果此队列为空,则返回 null
*
* @return
*/
public synchronized Object poll() {
if (isEmpty()) {
return null;
}
Object obj = peek();
//左移数组
leftMove(elementData,1);
elementCount--;
return obj;
}
/**
* 出队操作
* 获取并移除,如果此队列为空,则抛出NoSuchElementException异常
*
* @return
*/
public synchronized Object remove() {
if (isEmpty()) {
throw new NoSuchElementException();
}
Object obj = peek();
//左移数组
leftMove(elementData,1);
elementCount--;
return obj;
}
/**
* 判断队列是否为空
*/
public boolean isEmpty() {
return elementCount == 0;
}
/**
* 判断队列是否已满
*/
public boolean isFull() {
return elementCount == elementData.length;
}
/**
* 数组所有元素左移动x位
*
* @param arr
*/
public void leftMove(Object[] arr, int x) {
for (int i = 0; i < arr.length; i++) {
if (i >= arr.length - x) {
arr[i] = null;
continue;
}
arr[i] = arr[i + x];
}
}
@Test
public void test() {
MyQueue queue = new MyQueue();
for (int i = 0; i < 70; i++) {
queue.offer("data" + i);
}
for (int i = 0; i < 70; i++) {
System.out.println(queue.poll());
}
}
}
3、基于数组的单向队列优化方案
因为出队操作都相当于删除数组下标为 0 的数据,要搬移整个队列中的数据,这样出队操作的时间复杂度就会从原来的 O(1) 变为 O(n)。
优化方案,维护两个指针,一个是 head 指针,指向队头;一个是 tail 指针,指向队尾。出队时可以不用搬移数据。如果没有空闲空间了,我们只需要在入队时,再集中触发一次数据的搬移操作。
/**
* description: 基于数组实现队列(基于头尾指针维护队列)
* date: 2019/8/21
* author: wp
*/
public class MyQueue {
/**
* 容器
*/
private Object[] elementData;
/**
* 队列的默认大小
*/
private static final int DEFAULT_SIZE = 10;
/**
* 队列中头指针
*/
private int head;
/**
* 队列中尾指针
*/
private int tail;
/**
* 默认构造器
*/
public MyQueue() {
this(DEFAULT_SIZE);
}
/**
* 指定队列的容量构造器
*/
public MyQueue(int size) {
if (size < 0) {
throw new RuntimeException();
}
elementData = new Object[size];
}
/**
* 入队操作
* 将指定的元素插入此队列,(如果违反容量限制抛出IllegalStateException)
*
* @param obj
* @return
*/
public synchronized boolean add(Object obj) {
if (isFull()) {
//队列满了
throw new IllegalStateException();
}
elementData[tail] = obj;
tail++;
return true;
}
/**
* 入队操作
* 将指定的元素插入此队列,(如果违反容量限制不抛异常)
*
* @param obj
* @return
*/
public synchronized boolean offer(Object obj) {
//队列满了
if (isFull()) {
//这时候集中删除触发一次数据搬移
if (head > 0) {
leftMove(elementData, head);
tail = tail - head;
head = 0;
} else {
Object[] temp = elementData;
elementData = new Object[elementData.length * 2];
System.arraycopy(temp, 0, elementData, 0, temp.length);
}
}
elementData[tail] = obj;
tail++;
return true;
}
/**
* 出队操作
* 获取但不移除, 如果此队列为空,则返回 null
*
* @return
*/
public Object peek() {
if (!isEmpty()) {
return elementData[head];
}
return null;
}
/**
* 出队操作
* 获取但不移除, 如果此队列为空,则返回 null,如果此队列为空,则将抛出NoSuchElementException异常
*
* @return
*/
public synchronized Object element() {
if (isEmpty()) {
throw new NoSuchElementException();
}
return elementData[head];
}
/**
* 出队操作
* 获取并移除, 如果此队列为空,则返回 null
*
* @return
*/
public synchronized Object poll() {
if (isEmpty()) {
return null;
}
Object obj = peek();
//头指针后移一位
head++;
return obj;
}
/**
* 出队操作
* 获取并移除,如果此队列为空,则抛出NoSuchElementException异常
*
* @return
*/
public synchronized Object remove() {
if (isEmpty()) {
throw new NoSuchElementException();
}
Object obj = peek();
//头指针后移一位
head++;
return obj;
}
/**
* 判断队列是否为空
*/
public boolean isEmpty() {
return head == tail;
}
/**
* 判断队列是否已满
*/
public boolean isFull() {
return tail == elementData.length;
}
/**
* 数组所有元素左移动x位
*
* @param arr
*/
public void leftMove(Object[] arr, int x) {
for (int i = 0; i < arr.length; i++) {
if (i >= arr.length - x) {
arr[i] = null;
continue;
}
arr[i] = arr[i + x];
}
}
}