·  阅读 451

# 1 优先队列应用

## 1.1 应用一

``````// 优先级 P1 > P2 > p3
public enum PriorityEnum {

P1(1, "优先级1"),

P2(2, "优先级2"),

P3(3, "优先级3")

;
}

``````public class MyMessage implements Comparable {

/**
* 消息优先级
*/
private int priority;

/**
* 消息内容
*/
private String messge;

public MyMessage(int priority, String message) {
this.priority = priority;
this.messge = message;
}

@Override
public int compareTo(Object obj) {
MyMessage message = (MyMessage) obj;
return this.priority - message.priority;
}
}

java.util.PriorityQueue可以实现上述功能：

``````public class PriorityQueueTest {
public static void main(String[] args) {
PriorityQueue<MyMessage> messageQueue = new PriorityQueue<MyMessage>();
MyMessage m1 = new MyMessage(PriorityEnum.P1.getCode(), "message1");
MyMessage m2 = new MyMessage(PriorityEnum.P2.getCode(), "message2");
MyMessage m3 = new MyMessage(PriorityEnum.P3.getCode(), "message3");
messageQueue.offer(m3);
messageQueue.offer(m1);
messageQueue.offer(m2);
while (messageQueue.size() > 0) {
System.out.println(messageQueue.poll());
}
}
}

``````send message=MyMessage(priority=1, messge=message1)
send message=MyMessage(priority=2, messge=message2)
send message=MyMessage(priority=3, messge=message3)

PriorityQueueTest消息放入优先队列顺序：

``````3、1、2

PriorityQueueTest从优先队列获取消息顺序：

``````1、2、3

## 1.2 应用二

``````// 优先级 P3 > P2 > p1
public enum PriorityEnum {

P1(1, "优先级1"),

P2(2, "优先级2"),

P3(3, "优先级3")

;
}

``````3、2、1

``````public class MyMessage implements Comparable {

@Override
public int compareTo(Object obj) {
MyMessage message = (MyMessage) obj;
return message.priority - this.priority; // 比较关系变更
}
}

# 2 二叉堆

## 2.2 怎样存储二叉堆

``````int[] array = new int[10]

``````array[0] = 100

``````leftChildIndex = (parentIndex * 2) + 1
rightChildIndex = (parentIndex * 2) + 2

``````parentIndex = 0
leftChildIndex = (0 * 2) + 1 = 1
array[1] = 90

``````parentIndex = 0
leftChildIndex = (0 * 2) + 2 = 2
array[2] = 80

``````parentIndex = 2
leftChildIndex = (2 * 2) + 2 = 6
array[6] = 30

``````parentIndex = (childIndex - 1) / 2

``````childIndex = 6
parentIndex = (6 - 1) / 2 = 2

# 3 手写大顶堆

## 3.1 接口声明

``````public interface IMaxHeap<E extends Comparable> {

/**
* 新增元素
*
* @param element 待新增元素
* @return true表示成功
*/
public boolean offer(E element);

/**
* 获取并删除堆顶元素
*
* @return 最大值
*/
public E getAndRemoveTop();

/**
* 堆大小
*
* @return 堆大小
*/
public int size();
}

## 3.2 大顶堆实现

``````public class MyMaxHeap<E extends Comparable> implements IMaxHeap<E> {

private ArrayList<E> array;

public MyMaxHeap() {
array = new ArrayList<E>();
}

@Override
public boolean offer(E element) {
// 新增至数组最后
int lastIndex = size();

// 节点上浮
siftUp(lastIndex);

// 新增成功
return Boolean.TRUE;
}

@Override
public E getAndRemoveTop() {
// 根节点为最大值
E top = array.get(0);

// 最后一个节点删除并移动至堆顶
int lastIndex = size() - 1;
E lastNode = array.get(lastIndex);
array.remove(lastIndex);
array.set(0, lastNode);

// 节点下沉
siftDown(0);

// 返回最大值
}

@Override
public int size() {
return array.size();
}

// 节点上浮
private void siftUp(int currentIndex) {
// 根节点无需上浮
while (currentIndex != 0) {
// 当前节点
E currentValue = array.get(currentIndex);
// 父索引
int parentIndex = HeapUtil.getParentIndex(currentIndex);
// 父节点
E parentValue = array.get(parentIndex);
// 当前节点小于父节点则退出循环
if (currentValue.compareTo(parentValue) < 0) {
break;
}
// 当前节点大于等于父节点则交换位置
array.set(parentIndex, currentValue);
array.set(currentIndex, parentValue);
currentIndex = parentIndex;
}
}

// 节点下沉
private void siftDown(int currentIndex) {
// 当前节点没有左子节点则无需下沉
while (HeapUtil.getLeftChildIndex(currentIndex) < size()) {
// 当前节点
E currentValue = array.get(currentIndex);
// 左子索引
int leftChildIndex = HeapUtil.getLeftChildIndex(currentIndex);
// 左子节点
E leftChildValue = array.get(leftChildIndex);
// 右子索引
Integer rightChildIndex = null;
// 右子节点
E rightChildValue = null;
// 右子节点是否存在
if (HeapUtil.getRightChildIndex(currentIndex) < size()) {
rightChildIndex = HeapUtil.getRightChildIndex(currentIndex);
rightChildValue = array.get(rightChildIndex);
}
// 右子节点存在
if (null != rightChildIndex) {
// 找出左右子节点较大节点
int biggerIndex = rightChildIndex;
if (leftChildValue.compareTo(rightChildValue) > 0) {
biggerIndex = leftChildIndex;
}
// 较大节点小于当前节点则退出循环
E biggerValue = array.get(biggerIndex);
if (biggerValue.compareTo(currentValue) < 0) {
break;
}
// 较大节点大于等于当前节点则交换位置
array.set(currentIndex, biggerValue);
array.set(biggerIndex, currentValue);
currentIndex = biggerIndex;
}
// 右子节点不存在
else {
// 左子节点小于当前节点则退出循环
if (leftChildValue.compareTo(currentValue) < 0) {
break;
}
// 左子节点大于等于当前节点则交换位置
array.set(currentIndex, leftChildValue);
array.set(leftChildIndex, currentValue);
currentIndex = leftChildIndex;
}
}
}
}

public class HeapUtil {

// 获取左子节点索引
public static int getLeftChildIndex(int currentIndex) {
return currentIndex * 2 + 1;
}

// 获取右子节点索引
public static int getRightChildIndex(int currentIndex) {
return currentIndex * 2 + 2;
}

// 获取父节点索引
public static int getParentIndex(int currentIndex) {
if (currentIndex == 0) {
throw new RuntimeException("root node has no parent");
}
return (currentIndex - 1) / 2;
}
}

## 3.3 代码测试

``````public class MyMaxHeapTest {
public static void main(String[] args) {
MyMaxHeap<Integer> maxHeap = new MyMaxHeap<Integer>();
maxHeap.offer(70);
maxHeap.offer(90);
maxHeap.offer(80);
maxHeap.offer(100);
maxHeap.offer(60);
System.out.println("maxHeap test offer, heapInfo=" + maxHeap);
Integer maxValue = maxHeap.getAndRemoveTop();
System.out.println("maxHeap test getAndRemoveTop, maxValue=" + maxValue + ", heapInfo=" + maxHeap);
}
}

``````maxHeap test offer, heapInfo=[100, 90, 80, 70, 60]
maxHeap test getAndRemoveTop, maxValue=100, heapInfo=[90, 70, 80, 60]

# 4 手写优先队列

## 4.1 接口声明

``````public interface IPriorityQueue<E extends Comparable> {

/**
* 新增元素
*
* @param element 元素
*/
public void offer(E element);

/**
* 获取队列首元素
*
* @return 首元素
*/
public E poll();

/**
* 获取队列长度
*
* @return 队列长度
*/
public int size();
}

## 4.2 优先队列实现

``````public class MyPriorityQueue<E extends Comparable> implements IPriorityQueue<E> {

private MyMaxHeap<E> myMaxHeap;

public MyPriorityQueue() {
myMaxHeap = new MyMaxHeap<E>();
}

@Override
public void offer(E element) {
myMaxHeap.offer(element);
}

@Override
public E poll() {
return myMaxHeap.getAndRemoveTop();
}

@Override
public int size() {
return myMaxHeap.size();
}
}

## 4.3 代码测试

``````public class PriorityQueueTest {
public static void main(String[] args) {
MyPriorityQueue<Integer> myPriorityQueue = new MyPriorityQueue<Integer>();
myPriorityQueue.offer(10);
myPriorityQueue.offer(30);
myPriorityQueue.offer(20);
while (myPriorityQueue.size() > 0) {
System.out.println(myPriorityQueue.poll());
}
}
}

``````30
20
10

# 5 源码分析

## 5.1 JDK PriorityQueue

``````package java.util;

public class PriorityQueue<E> extends AbstractQueue<E> implements java.io.Serializable {

private static final int DEFAULT_INITIAL_CAPACITY = 11;

transient Object[] queue;

private int size = 0;

private final Comparator<? super E> comparator;

public PriorityQueue() {
this(DEFAULT_INITIAL_CAPACITY, null);
}

public PriorityQueue(Comparator<? super E> comparator) {
this(DEFAULT_INITIAL_CAPACITY, comparator);
}

// 新增元素
public boolean offer(E e) {
if (e == null)
throw new NullPointerException();
modCount++;
int i = size;
if (i >= queue.length)
grow(i + 1);
size = i + 1;
if (i == 0)
queue[0] = e;
else
// 上浮
siftUp(i, e);
return true;
}

private void siftUp(int k, E x) {
if (comparator != null)
siftUpUsingComparator(k, x);
else
siftUpComparable(k, x);
}

private void siftUpComparable(int k, E x) {
Comparable<? super E> key = (Comparable<? super E>) x;
while (k > 0) {
// 父索引
int parent = (k - 1) >>> 1;
// 父节点
Object e = queue[parent];
// 当前节点大于等于父节点则退出循环
if (key.compareTo((E) e) >= 0)
break;
// 当前节点小于父节点则交换位置上浮
queue[k] = e;
k = parent;
}
queue[k] = key;
}

// 获取并删除队首元素
public E poll() {
if (size == 0)
return null;
int s = --size;
modCount++;
E result = (E) queue[0];
E x = (E) queue[s];
queue[s] = null;
if (s != 0)
// 下沉
siftDown(0, x);
return result;
}

private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}

private void siftDownComparable(int k, E x) {
Comparable<? super E> key = (Comparable<? super E>)x;
int half = size >>> 1;
while (k < half) {
// 左子索引
int child = (k << 1) + 1;
// 左子节点
Object c = queue[child];
// 右子索引
int right = child + 1;
// 比较左右子节点较大节点
if (right < size && ((Comparable<? super E>) c).compareTo((E) queue[right]) > 0)
c = queue[child = right];
// 当前节点小于等于较大节点则退出循环
if (key.compareTo((E) c) <= 0)
break;
// 当前节点大于较大节点则交换位置下沉
queue[k] = c;
k = child;
}
queue[k] = key;
}
}

## 5.2 JDK DelayQueue

``````package java.util.concurrent;

public class DelayQueue<E extends Delayed> extends AbstractQueue<E> implements BlockingQueue<E> {

private final transient ReentrantLock lock = new ReentrantLock();
private final PriorityQueue<E> q = new PriorityQueue<E>();

public boolean offer(E e) {
final ReentrantLock lock = this.lock;
lock.lock();
try {
q.offer(e);
if (q.peek() == e) {
available.signal();
}
return true;
} finally {
lock.unlock();
}
}

public E poll() {
final ReentrantLock lock = this.lock;
lock.lock();
try {
// 获取队首元素
E first = q.peek();
// 队首元素时间大于当前时间表示没到期
if (first == null || first.getDelay(NANOSECONDS) > 0)
return null;
// 队首元素时间小于等于当前时间表示到期则取出并删除
else
return q.poll();
} finally {
lock.unlock();
}
}
}