版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
堆的特点
- 堆是一棵完全二叉树
- 父节点大于子节点
堆的实现
package geektime.sort;
import java.util.ArrayList;
import java.util.List;
// 大顶堆
public class MaxHeap<E extends Comparable<E>> {
private List<E> data;
public MaxHeap() {
this.data = new ArrayList<>();
}
public MaxHeap(E[] es) {
this();
buildHeap(es);
}
public void add(E e) {
//将新数据添加到末尾
this.data.add(e);
//堆末尾元素进行上浮堆化
siftUp(this.data.size(), this.data.size() - 1);
}
public E getMax() {
return this.data.get(0);
}
//获取并删除堆定元素
public E extractMax() {
E max = this.data.get(0);
swap(0, this.data.size() - 1);
this.data.remove(this.data.size() - 1);
siftDown(this.data.size(), 0);
return max;
}
/**
* 堆排序
* */
public void heapSort(){
for (int i = this.data.size() - 1;i >=0;i --) {
swap(0, i);
siftDown(i, 0);
}
}
private void buildHeap(E[] es) {
//将元素添加到容器中
for (E value : es) { this.data.add(value); }
//找到第一个不是叶子节点到节点,堆其进行向下堆化
for (int i = getParent(this.data.size() - 1);i >= 0;i --) {
siftDown(this.data.size(), i);
}
}
//上浮堆化
private void siftUp(int len, int idx) {
//如果当前节点值比父节点值大,那么进行交换,知道找到根节点
while (getParent(idx) >= 0 && this.data.get(idx).compareTo(this.data.get(getParent(idx))) > 0) {
swap(idx, getParent(idx));
idx = getParent(idx);
}
}
//下沉堆化
private void siftDown(int len, int idx) {
while (getLeft(idx) < len) {
//找到左右节点中最大的那个
int tempIdx = getLeft(idx);
if (getRight(idx) < len && this.data.get(getRight(idx)).compareTo(this.data.get(tempIdx)) > 0) {
tempIdx = getRight(idx);
}
//如果当前节点比两个子节点都打,那么就不需要后续都交换
if(this.data.get(idx).compareTo(this.data.get(tempIdx)) > 0) {
break;
}else {
swap(idx, tempIdx);
idx = tempIdx;
}
}
}
private int getParent(int index) { return (index - 1) / 2; }
private int getLeft(int index) { return index * 2 + 1; }
private int getRight(int index) { return index * 2 + 2; }
private void swap(int idx1, int idx2) {
E temp = data.get(idx1);
data.set(idx1, data.get(idx2));
data.set(idx2, temp);
}
public void print() {
data.stream().forEach(v -> System.out.print( v + " "));
System.out.println();
}
public static void main(String[] args) {
Integer[] arr = {1,5,2,6,8,3};
MaxHeap<Integer> maxHeap = new MaxHeap<>(arr);
//maxHeap.heapSort();
maxHeap.print();//8 6 3 1 5 2
maxHeap.add(0);
maxHeap.add(55);
maxHeap.print();//55 8 3 6 5 2 0 1
System.out.println(maxHeap.extractMax());
maxHeap.print();
maxHeap.heapSort();
maxHeap.print();//0 1 2 3 5 6 8 55
}
}
用堆实现优先级队列
package geektime.sort;
public class PriorityQueue<E extends Comparable<E>> {
private MaxHeap<E> maxHeap;
public PriorityQueue() {
this.maxHeap = new MaxHeap<>();
}
public void enqueue(E e) {
this.maxHeap.add(e);
}
public E dequeue(){
return this.maxHeap.extractMax();
}
public static void main(String[] args) {
PriorityQueue<Integer> queue = new PriorityQueue<>();
queue.enqueue(1);
queue.enqueue(2);
queue.enqueue(3);
System.out.println(queue.dequeue()); // 3
System.out.println(queue.dequeue()); // 2
System.out.println(queue.dequeue()); // 1
}
}
时间复杂度
- 插入元素 O(logN)
- 删除元素 O(logN)
- 排队 O(NlogN)