堆是一种基于完全二叉树的数据结构,它分为大根堆和小根堆。在大根堆中,每个节点的值都大于或等于其子节点的值;而在小根堆中,每个节点的值都小于或等于其子节点的值。
在Java中,我们可以使用数组来表示堆。由于完全二叉树的性质,我们可以将堆的节点按照从上到下、从左到右的顺序对应到数组中。假设堆的根节点在数组中的下标为0,则其左孩子的下标为2i+1,右孩子的下标为2i+2,父节点的下标为(i-1)/2。
以下是使用Java实现堆的代码:
public class Heap {
private int[] heap; // 堆
private int size; // 堆的大小
public Heap(int[] heap) {
this.heap = heap;
this.size = heap.length;
buildHeap();
}
// 堆排序
public void sort() {
while (size > 1) {
swap(0, size - 1);
size--;
heapify(0);
}
}
// 构建堆
private void buildHeap() {
for (int i = (size - 2) / 2; i >= 0; i--) {
heapify(i);
}
}
// 堆化
private void heapify(int i) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int max = i;
if (left < size && heap[left] > heap[max]) {
max = left;
}
if (right < size && heap[right] > heap[max]) {
max = right;
}
if (max != i) {
swap(i, max);
heapify(max);
}
}
// 交换元素
private void swap(int i, int j) {
int temp = heap[i];
heap[i] = heap[j];
heap[j] = temp;
}
}
上述代码实现了一个最大堆,堆的大小为数组的长度。堆排序的思路与普通的堆排序一致,先建立堆,然后每次将堆顶元素与堆底元素交换,缩小堆的大小,并重新堆化。
对于一个包含n个元素的数组,建立堆的时间复杂度为O(n),堆排序的时间复杂度为O(nlogn)。由于堆排序的空间复杂度为O(1),因此它是一种原地排序算法。