优先队列
- Java中没有一个叫做Heap的类,确有一个可以实现和堆一样功能的类
PriorityQueue
,即优先队列。 - 从名字可以看出,它其实是一个队列,这个队列和其他队列一样有一个入口,一个出口,不一样的地方就是,每个进入队列的元素都有一个优先级,在队列里的顺序就是根据优先级来排序的,优先级高的就会排在队列的前面,优先级低的就会在队列的后面。
- 每个元素入队的时候,就会根据自己的价值来确定一个优先级。这个优先级是会随着元素的增加或减少而变化的。
PriorityQueue使用
- 实现一个优先队列,最重要的是去制定一个规则来确定每个元素的优先级,这个规则制定之后,PriorityQueue会根据这个规则来自动的进行排序。
- 这个规则就是两两之间怎么确定那个优先级高,哪个低。这时候需要一个比较器
Comparator<T>
.
这只是一个接口,具体的逻辑需要具体实现。
Comparator<Integer> comparator = new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
return o1 - o2;
}
};
也可以直接用lambda表达式
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>
((o1, o2) -> o1-o2);
这样的结果是形成一个小根堆,o1-o2<0 则o1在前面o2在后面。这个比较器的规则就是数字越小,优先级越高。这样的结果相当于从小到大排序。
public PriorityQueue(int initialCapacity)
public PriorityQueue(int initialCapacity, Comparator<? super E> comparator)
第一个构造函数是给定一个初始的大小,因为没有传比较器,所以默认是从小到大。
add() 和 poll()
- PriorityQueue在使用的过程中最常使用的就是添加一个元素add(),弹出一个元素poll()。
- 当调用add(E)方法时,PriorityQueue会自己进行比较,然后排序。PriorityQueue内部维护了一个堆,add方法相当于在这个堆的底部添加了一个元素,然后在从底部一直往上去寻找自己合适的位置(根据比较器)。
- poll()方法就是将堆顶的元素弹出,并重新整理堆,再次形成一个小根堆。
堆(heap)
堆分为大根堆和小根堆两种。堆的实质是一棵特殊的完全二叉树。
- 小根堆:该二叉树的根节点的值是最小的,而且每个节点不大于自己的子节点。
- 大根堆:该二叉树的根节点的值是最大的,而且每个节点不小于自己的子节点。
构建堆
https://www.cnblogs.com/chengxiao/p/6129630.html
- 堆排序首先需要构建一个堆
//Priority 的一个构造函数,以一个集合为基础构建一个堆。
public PriorityQueue(Collection<? extends E> c);
//构建堆的方法
private void heapify() {
for (int i = (size >>> 1) - 1; i >= 0; i--)
siftDown(i, (E) queue[i]);
}
//向下调整
private void siftDown(int k, E x) {
if (comparator != null)
siftDownUsingComparator(k, x);
else
siftDownComparable(k, x);
}
private void siftDownUsingComparator(int k, 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 &&
comparator.compare((E) c, (E) queue[right]) > 0)
c = queue[child = right];
if (comparator.compare(x, (E) c) <= 0)
break;
queue[k] = c;
k = child;
}
queue[k] = x;
}
siftUp
优先队列的主要方法就是siftUp
每次当插入一个新的节点时,节点先被插入完全二叉树的最后,再调用siftUp
方法,如果小于父节点(小根堆)就和父节点进行交换,进行递归操作,直到不小于父节点。
private void siftUp(int k, E x) {
if (comparator != null)
siftUpUsingComparator(k, x, queue, comparator);
else
siftUpComparable(k, x, queue);
}
private void siftUpUsingComparator(int k, E x) {
while (k > 0) {
int parent = (k - 1) >>> 1;
Object e = queue[parent];
if (comparator.compare(x, (E) e) >= 0)
break;
queue[k] = e;
k = parent;
}
queue[k] = x;
}
poll
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;
}