一、和普通队列比较
关键:动态
入队和队列一致, 出队的时候有一个优先级,优先级高的优先出队
二、时间复杂度比较
| 入队 | 出队(拿出最大元素) | |
|---|---|---|
| 普通线性结构 | O(1) | O(n) |
| 顺序线性结构 | O(n) | O(1) |
| 堆 | O(logn) | O(logn) |
三、堆 -Heap
二叉堆(Binary Heap)是一棵完全二叉树:
- 把一棵树的放完
- 某个节点总是不大于其parent节点 通常也叫最大堆
四、添加元素 -Sift Up
// 向堆中添加元素
public void add(E e){
data.addLast(e);
siftUp(data.getSize() - 1);
}
private void siftUp(int k){
while(k > 0 && data.get(parent(k)).compareTo(data.get(k)) < 0 ){
//交换和父亲节点的位置
data.swap(k, parent(k));
k = parent(k);
}
}
五、取出堆中的最大元素和Sift Down
- Sift Down
- 用最小元素替换堆顶元素,然后删除之前的最小元素位置
- 最小元素和子树中最大元素,比较,交换位置
- 下沉完毕
// 看堆中的最大元素
public E findMax(){
if(data.getSize() == 0)
throw new IllegalArgumentException("Can not findMax when heap is empty.");
return data.get(0);
}
取出最大元素
// 取出堆中最大元素
public E extractMax(){
E ret = findMax();
data.swap(0, data.getSize() - 1);
data.removeLast();
siftDown(0);
return ret;
}
下浮sift down
private void siftDown(int k){
// k的左子树成为叶子节点
// 在此轮循环中,data[k]和data[j]交换位置,也就是父亲节点和孩子节点进行交换
while(leftChild(k) < data.getSize()){
//j存储的是左孩子的索引
int j = leftChild(k);
// j + 1 < data.getSize()说明有右孩子
// j存储右孩子的索引(如果右比左大的话)
if( j + 1 < data.getSize() &&
data.get(j + 1).compareTo(data.get(j)) > 0 )
//j ++ 后变成右孩子的索引
j ++;
// data[j] 是 leftChild 和 rightChild 中的最大值
if(data.get(k).compareTo(data.get(j)) >= 0 )
break;
data.swap(k, j);
k = j;
}
}