内容来自刘宇波老师算法与数据结构体系课
1、堆的结构

2、建堆方式
| 1、将 n 个元素逐个插⼊到⼀个空堆中,算法复杂度是 O(N * logN) |
| 2、heapify:从最后一个非叶子节点开始,从后向前,倒序进行 siftDown 操作,算法复杂度为 O(n) |

3、实现最大堆
| |
| |
| |
| |
| public class MaxHeap<E extends Comparable<E>> { |
| |
| private Array<E> data; |
| |
| public MaxHeap() { |
| data = new Array<>(); |
| } |
| |
| public MaxHeap(int capacity) { |
| data = new Array<>(capacity); |
| } |
| |
| public MaxHeap(E[] arr) { |
| heapify(arr); |
| } |
| |
| public int size() { |
| return data.getSize(); |
| } |
| |
| public boolean isEmpty() { |
| return data.isEmpty(); |
| } |
| |
| |
| |
| |
| private int parent(int index) { |
| if (index == 0) throw new IllegalArgumentException("index-0 doesn't have parent."); |
| return (index - 1) / 2; |
| } |
| |
| |
| |
| |
| private int leftChild(int index) { |
| return index * 2 + 1; |
| } |
| |
| |
| |
| |
| private int rightChild(int index) { |
| return index * 2 + 2; |
| } |
| |
| |
| |
| |
| private void siftUp(int index) { |
| while (index > 0 && data.get(index).compareTo(data.get(parent(index))) > 0) { |
| data.swap(index, parent(index)); |
| index = parent(index); |
| } |
| } |
| |
| |
| |
| |
| private void siftDown(int index) { |
| while (leftChild(index) < data.getSize()) { |
| int bigger = leftChild(index); |
| if (bigger + 1 < data.getSize() && data.get(bigger + 1).compareTo(data.get(bigger)) > 0) bigger++; |
| |
| if (data.get(index).compareTo(data.get(bigger)) >= 0) break; |
| data.swap(index, bigger); |
| index = bigger; |
| } |
| } |
| |
| |
| |
| |
| |
| private void heapify(E[] arr) { |
| data = new Array<>(arr); |
| for (int i = parent(data.getSize() - 1); i >= 0; i--) siftDown(i); |
| } |
| |
| |
| |
| |
| public void add(E e) { |
| data.addLast(e); |
| siftUp(data.getSize() - 1); |
| } |
| |
| |
| |
| |
| public E findMax() { |
| if (isEmpty()) throw new RuntimeException("Heap is empty!"); |
| return data.get(0); |
| } |
| |
| |
| |
| |
| public E extractMax() { |
| E max = findMax(); |
| data.swap(0, data.getSize() - 1); |
| data.removeLast(); |
| siftDown(0); |
| return max; |
| } |
| |
| |
| |
| |
| public E replace(E e) { |
| E max = findMax(); |
| data.set(0, e); |
| siftDown(0); |
| return max; |
| } |
| } |
4、实现最小堆
| |
| |
| |
| |
| public class MinHeap<E extends Comparable<E>> { |
| |
| private Array<E> data; |
| |
| public MinHeap() { |
| data = new Array<>(); |
| } |
| |
| public MinHeap(int capacity) { |
| data = new Array<>(capacity); |
| } |
| |
| public MinHeap(E[] arr) { |
| heapify(arr); |
| } |
| |
| public int size() { |
| return data.getSize(); |
| } |
| |
| public boolean isEmpty() { |
| return data.isEmpty(); |
| } |
| |
| private int parent(int index) { |
| if (index == 0) throw new IllegalArgumentException("index-0 doesn't have parent."); |
| return (index - 1) / 2; |
| } |
| |
| private int leftChild(int index) { |
| return index * 2 + 1; |
| } |
| |
| private int rightChild(int index) { |
| return index * 2 + 2; |
| } |
| |
| private void siftUp(int index) { |
| while (index > 0 && data.get(index).compareTo(data.get(parent(index))) < 0) { |
| data.swap(index, parent(index)); |
| index = parent(index); |
| } |
| } |
| |
| private void siftDown(int index) { |
| while (leftChild(index) < data.getSize()) { |
| int smaller = leftChild(index); |
| if (smaller + 1 < data.getSize() && data.get(smaller + 1).compareTo(data.get(smaller)) < 0) smaller++; |
| |
| if (data.get(index).compareTo(data.get(smaller)) <= 0) break; |
| data.swap(index, smaller); |
| index = smaller; |
| } |
| } |
| |
| private void heapify(E[] arr) { |
| data = new Array<>(arr); |
| for (int i = parent(data.getSize() - 1); i >= 0; i--) siftDown(i); |
| } |
| |
| public void add(E e) { |
| data.addLast(e); |
| siftUp(data.getSize() - 1); |
| } |
| |
| public E findMin() { |
| if (isEmpty()) throw new RuntimeException("Heap is empty!"); |
| return data.get(0); |
| } |
| |
| public E extractMin() { |
| E min = findMin(); |
| data.swap(0, data.getSize() - 1); |
| data.removeLast(); |
| siftDown(0); |
| return min; |
| } |
| |
| public E replace(E e) { |
| E min = findMin(); |
| data.set(0, e); |
| siftDown(0); |
| return min; |
| } |
| } |
5、优先队列
| public interface Queue<E> { |
| |
| void enqueue(E e); |
| |
| E dequeue(); |
| |
| E getFront(); |
| |
| int getSize(); |
| |
| boolean isEmpty(); |
| |
| } |
| |
| |
| |
| public class PriorityQueue<E extends Comparable<E>> implements Queue<E> { |
| |
| private final MaxHeap<E> maxHeap; |
| |
| public PriorityQueue() { |
| maxHeap = new MaxHeap<>(); |
| } |
| |
| @Override |
| public void enqueue(E e) { |
| maxHeap.add(e); |
| } |
| |
| @Override |
| public E dequeue() { |
| return maxHeap.extractMax(); |
| } |
| |
| @Override |
| public E getFront() { |
| return maxHeap.findMax(); |
| } |
| |
| @Override |
| public int getSize() { |
| return maxHeap.size(); |
| } |
| |
| @Override |
| public boolean isEmpty() { |
| return maxHeap.isEmpty(); |
| } |
| } |
6、堆排序
| |
| |
| |
| |
| public class HeapSort { |
| |
| private HeapSort() { |
| } |
| |
| |
| |
| |
| public static <E extends Comparable<E>> void sort1(E[] arr) { |
| MaxHeap<E> maxHeap = new MaxHeap<>(); |
| for (E e : arr) maxHeap.add(e); |
| for (int i = arr.length - 1; i >= 0; i--) arr[i] = maxHeap.extractMax(); |
| } |
| |
| |
| |
| |
| public static <E extends Comparable<E>> void sort2(E[] arr) { |
| if (arr == null || arr.length <= 1) return; |
| |
| |
| int last = arr.length - 1; |
| for (int i = (last - 1) / 2; i >= 0; i--) siftDown(arr, i, last); |
| |
| while (last >= 1) { |
| swap(arr, 0, last); |
| last--; |
| siftDown(arr, 0, last); |
| } |
| } |
| |
| |
| |
| |
| private static <E extends Comparable<E>> void siftDown(E[] arr, int index, int last) { |
| while (index * 2 + 1 <= last) { |
| int bigger = index * 2 + 1; |
| if (bigger + 1 <= last && arr[bigger + 1].compareTo(arr[bigger]) > 0) bigger++; |
| |
| if (arr[index].compareTo(arr[bigger]) >= 0) break; |
| swap(arr, index, bigger); |
| index = bigger; |
| } |
| } |
| |
| private static <E> void swap(E[] arr, int a, int b) { |
| E k = arr[a]; |
| arr[a] = arr[b]; |
| arr[b] = k; |
| } |
| } |
| |
| |
| |
| |
| public class HeapSort { |
| |
| private HeapSort() { |
| } |
| |
| public static <E extends Comparable<E>> void sort1(E[] arr) { |
| MinHeap<E> minHeap = new MinHeap<>(); |
| for (E e : arr) minHeap.add(e); |
| for (int i = arr.length - 1; i >= 0; i--) arr[i] = minHeap.extractMin(); |
| } |
| |
| public static <E extends Comparable<E>> void sort2(E[] arr) { |
| if (arr == null || arr.length <= 1) return; |
| |
| int last = arr.length - 1; |
| for (int i = (last - 1) / 2; i >= 0; i--) siftDown(arr, i, last); |
| |
| while (last >= 1) { |
| swap(arr, 0, last); |
| last--; |
| siftDown(arr, 0, last); |
| } |
| } |
| |
| |
| |
| |
| private static <E extends Comparable<E>> void siftDown(E[] arr, int index, int last) { |
| while (index * 2 + 1 <= last) { |
| int smaller = index * 2 + 1; |
| if (smaller + 1 <= last && arr[smaller + 1].compareTo(arr[smaller]) < 0) smaller++; |
| |
| if (arr[index].compareTo(arr[smaller]) <= 0) break; |
| swap(arr, index, smaller); |
| index = smaller; |
| } |
| } |
| |
| private static <E> void swap(E[] arr, int a, int b) { |
| E k = arr[a]; |
| arr[a] = arr[b]; |
| arr[b] = k; |
| } |
| } |
7、Select K 与 Top K 问题
另一种思路,利用快排思想解决 Select K 与 Top K 问题

7.1、Select K 问题
215 - 数组中的第 K 个最大元素
| |
| |
| |
| |
| |
| public class FindKthLargest { |
| |
| public static int findKthLargest(int[] arr, int k) { |
| int[] minHeap = Arrays.copyOf(arr, k); |
| int last = k - 1; |
| for (int i = (last - 1) / 2; i >= 0; i--) siftDown(minHeap, i); |
| |
| for (int i = k; i < arr.length; i++) { |
| if (arr[i] > minHeap[0]) { |
| minHeap[0] = arr[i]; |
| siftDown(minHeap, 0); |
| } |
| } |
| |
| return minHeap[0]; |
| } |
| |
| private static void siftDown(int[] arr, int index) { |
| int last = arr.length - 1; |
| while (index * 2 + 1 <= last) { |
| int smaller = index * 2 + 1; |
| if (smaller + 1 <= last && arr[smaller + 1] < arr[smaller]) smaller++; |
| |
| if (arr[index] <= arr[smaller]) break; |
| swap(arr, index, smaller); |
| index = smaller; |
| } |
| } |
| |
| private static void swap(int[] arr, int a, int b) { |
| int k = arr[a]; |
| arr[a] = arr[b]; |
| arr[b] = k; |
| } |
| } |
7.2、Top K 问题
剑指 Offer 40 - 最小的 K 个数
| |
| |
| |
| |
| |
| public class GetLeastNumbers { |
| |
| public static int[] getLeastNumbers(int[] arr, int k) { |
| if (k == 0) return new int[0]; |
| |
| int[] maxHeap = Arrays.copyOf(arr, k); |
| int last = k - 1; |
| for (int i = (last - 1) / 2; i >= 0; i--) siftDown(maxHeap, i); |
| |
| for (int i = k; i < arr.length; i++) { |
| if (arr[i] < maxHeap[0]) { |
| maxHeap[0] = arr[i]; |
| siftDown(maxHeap, 0); |
| } |
| } |
| |
| return maxHeap; |
| } |
| |
| private static void siftDown(int[] arr, int index) { |
| int last = arr.length - 1; |
| while (index * 2 + 1 <= last) { |
| int bigger = index * 2 + 1; |
| if (bigger + 1 <= last && arr[bigger + 1] > arr[bigger]) bigger++; |
| |
| if (arr[index] >= arr[bigger]) break; |
| swap(arr, index, bigger); |
| index = bigger; |
| } |
| } |
| |
| private static void swap(int[] arr, int a, int b) { |
| int k = arr[a]; |
| arr[a] = arr[b]; |
| arr[b] = k; |
| } |
| } |
8、快排思想和优先队列比较

9、更多话题
参考链接:索引堆、二项堆 1、二项堆 2、斐波那契堆
堆
- d 叉堆
- 索引堆:之前根据内容排序,现在根据索引排序
- 二项堆、斐波那契堆
广义队列

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步