上一篇
heap算法java
- 行业动态
- 2025-05-08
- 2649
Java堆算法基于数组实现,通过下沉调整维护堆性质,常用于优先队列
堆算法(Heap Algorithm)在Java中的实现与应用
堆的基本概念与性质
堆(Heap)是一种完全二叉树,分为最大堆(Max Heap)和最小堆(Min Heap),其核心性质如下:
类型 | 性质 |
---|---|
最大堆 | 任意节点的值大于或等于其子节点的值 |
最小堆 | 任意节点的值小于或等于其子节点的值 |
完全二叉树 | 所有层均被完全填充,除了最后一层可能未满,但最后一层的节点从左到右排列 |
堆的存储通常使用数组实现,父子节点的索引关系为:
- 父节点索引
i
的左子节点索引为2i + 1
- 父节点索引
i
的右子节点索引为2i + 2
- 子节点索引
j
的父节点索引为(j-1)/2
这种存储方式保证了堆的高效访问,时间复杂度为 O(1)
。
堆的核心操作
堆的核心操作包括插入(Insert)和删除(Delete),需维护堆的性质。
插入操作(以最大堆为例)
- 将新元素添加到数组末尾。
- 上浮(Sift Up):比较新元素与其父节点,若违反最大堆性质,则交换位置,直到满足条件或到达根节点。
代码示例(Java):
public void insert(int value) { array[size] = value; // 添加到末尾 int current = size; size++; // 上浮操作 while (current > 0) { int parent = (current 1) / 2; if (array[current] > array[parent]) { swap(current, parent); current = parent; } else { break; } } }
删除操作(以最大堆为例)
- 移除根节点(最大值),将最后一个元素移到根位置。
- 下沉(Sift Down):比较新根节点与其子节点,若违反最大堆性质,则与较大子节点交换,直到满足条件或成为叶子节点。
代码示例(Java):
public int delete() { int max = array[0]; array[0] = array[size 1]; // 用最后一个元素替换根 size--; // 下沉操作 int current = 0; while (current 2 + 1 < size) { // 非叶子节点 int leftChild = current 2 + 1; int rightChild = current 2 + 2; int largerChild = leftChild; if (rightChild < size && array[rightChild] > array[leftChild]) { largerChild = rightChild; } if (array[current] < array[largerChild]) { swap(current, largerChild); current = largerChild; } else { break; } } return max; }
堆排序(Heap Sort)
堆排序利用堆的特性实现升序排序,步骤如下:
- 将待排序数组构建成最大堆。
- 反复移除堆顶元素(当前最大值),并将其放到数组末尾,调整剩余堆。
- 最终得到升序数组。
时间复杂度:O(n log n)
(构建堆 O(n)
,每次删除 O(log n)
)。
代码示例(Java):
public void heapSort(int[] arr) { int n = arr.length; // 构建最大堆 for (int i = n / 2 1; i >= 0; i--) { siftDown(arr, n, i); } // 逐个提取元素 for (int i = n 1; i > 0; i--) { swap(arr, 0, i); // 将堆顶元素移到末尾 siftDown(arr, i, 0); // 调整剩余堆 } } private void siftDown(int[] arr, int n, int i) { int largest = i; int left = 2 i + 1; int right = 2 i + 2; if (left < n && arr[left] > arr[largest]) { largest = left; } if (right < n && arr[right] > arr[largest]) { largest = right; } if (largest != i) { swap(arr, i, largest); siftDown(arr, n, largest); } }
Java中的PriorityQueue
实现堆
Java标准库提供了PriorityQueue
,默认是最小堆,可通过自定义Comparator
实现最大堆。
示例:自定义最大堆
PriorityQueue<Integer> maxHeap = new PriorityQueue<>(Collections.reverseOrder()); maxHeap.offer(5); // 添加元素 maxHeap.offer(10); int max = maxHeap.poll(); // 获取并移除堆顶元素(最大值)
自定义堆的完整实现(Java)
以下是一个支持动态扩容的最小堆实现:
public class MinHeap { private int[] heap; private int size; private static final int CAPACITY = 10; public MinHeap() { heap = new int[CAPACITY]; size = 0; } public void insert(int value) { if (size == heap.length) { resize(); } heap[size] = value; int current = size; size++; // 上浮操作 while (current > 0) { int parent = (current 1) / 2; if (heap[current] < heap[parent]) { swap(current, parent); current = parent; } else { break; } } } public int remove() { if (size == 0) throw new IllegalStateException("Heap is empty"); int min = heap[0]; heap[0] = heap[size 1]; size--; // 下沉操作 int current = 0; while (current 2 + 1 < size) { int leftChild = current 2 + 1; int rightChild = current 2 + 2; int smallerChild = leftChild; if (rightChild < size && heap[rightChild] < heap[leftChild]) { smallerChild = rightChild; } if (heap[current] > heap[smallerChild]) { swap(current, smallerChild); current = smallerChild; } else { break; } } return min; } private void swap(int i, int j) { int temp = heap[i]; heap[i] = heap[j]; heap[j] = temp; } private void resize() { int[] newHeap = new int[heap.length 2]; System.arraycopy(heap, 0, newHeap, 0, heap.length); heap = newHeap; } }
FAQs(常见问题解答)
Q1:堆排序是否稳定?为什么?
A1:堆排序是不稳定的,因为在调整堆的过程中,可能会交换相等元素的相对位置,当两个相等元素分别位于左右子树时,下沉操作可能破坏它们的原始顺序。
Q2:堆的常见应用场景有哪些?
A2:堆的应用场景包括:
- 优先队列:快速获取最大或最小元素(如任务调度、事件处理)。
- 拓扑排序:用于有向无环图的排序。
- 中位数查找:使用两个堆(大顶堆和小顶堆)动态维护数据流的中位数。
- 合并多路有序数组:利用最小堆合并