堆(Heap)是一种特殊的完全二叉树,所有的节点都遵循堆的属性。在一个最大堆中,每个节点的值都大于或等于其子节点的值,而在一个最小堆中,每个节点的值都小于或等于其子节点的值。堆常用于实现优先队列,并且是堆排序算法的核心数据结构。
以下是使用Java实现一个最小堆的例子:
定义最小堆
public class MinHeap {
private int[] Heap;
private int size;
private int maxsize;
public MinHeap(int maxsize) {
this.maxsize = maxsize;
this.size = 0;
Heap = new int[this.maxsize + 1];
Heap[0] = Integer.MIN_VALUE; // 将堆数组的第一个元素设置为最小值,以便能使用简单整数除法找到父节点和子节点
}
// 返回当前节点的父节点位置
private int parent(int pos) {
return pos / 2;
}
// 返回左子节点的位置
private int leftChild(int pos) {
return (2 * pos);
}
// 返回右子节点的位置
private int rightChild(int pos) {
return (2 * pos) + 1;
}
// 交换两个节点的值
private void swap(int fpos, int spos) {
int tmp;
tmp = Heap[fpos];
Heap[fpos] = Heap[spos];
Heap[spos] = tmp;
}
// 如果当前节点的值小于其父节点,则向上移动(用于插入操作)
private void minHeapifyUp(int pos) {
int temp = Heap[pos];
while (pos > 1 && Heap[parent(pos)] > temp) {
Heap[pos] = Heap[parent(pos)];
pos = parent(pos);
}
Heap[pos] = temp;
}
// 如果当前节点的值大于其子节点之一,则向下移动(用于删除操作)
private void minHeapifyDown(int pos) {
int smallest = pos;
int left = leftChild(pos);
int right = rightChild(pos);
if (left <= size && Heap[left] < Heap[smallest]) {
smallest = left;
}
if (right <= size && Heap[right] < Heap[smallest]) {
smallest = right;
}
if (smallest != pos) {
swap(pos, smallest);
minHeapifyDown(smallest);
}
}
// 插入一个元素
public void insert(int element) {
if (size >= maxsize) {
return; // 堆已满
}
Heap[++size] = element;
minHeapifyUp(size);
}
// 移除并返回最小元素
public int extractMin() {
if (size == 0) {
throw new NoSuchElementException("Heap is empty");
}
int min = Heap[1];
Heap[1] = Heap[size--];
minHeapifyDown(1);
return min;
}
}
使用最小堆
public class Main {
public static void main(String[] args) {
MinHeap minHeap = new MinHeap(10);
minHeap.insert(5);
minHeap.insert(3);
minHeap.insert(17);
minHeap.insert(10);
minHeap.insert(84);
minHeap.insert(19);
minHeap.insert(6);
minHeap.insert(22);
minHeap.insert(9);
// 提取最小值,也就是根节点的值
System.out.println("The Min val is " + minHeap.extractMin()); // 输出 3
}
}
在上面的示例中,我们定义了一个最小堆,并实现了insert
方法来向堆中添加元素,以及extractMin
方法来删除并返回堆中的最小元素。堆的性质通过minHeapifyUp
和minHeapifyDown
方法进行维护。
在实际应用中,Java标准库提供了PriorityQueue
类,它内部使用了堆数据结构,通常可以直接使用这个类,而不必自己实现堆。例如:
PriorityQueue<Integer> minHeap = new PriorityQueue<>();
minHeap.add(5);
minHeap.add(3);
minHeap.add(17);
// ...
int min = minHeap.poll(); // 自动获取并删除最小元素
PriorityQueue
类在默认情况下实现了最小堆,如果需要最大堆,则可以提供自定义的比较器。使用PriorityQueue
不仅减少了开发时间,而且因为它是经过充分测试和优化的,所以在性能上通常也会更好。