- 堆结构是用数组实现的完全二叉树结构
- 完全二叉树 中 如果 每颗子树的最大值在顶部, 就是大根堆
- 完全二叉树 中 如果 每颗子树的最小值在顶部, 就是小根堆
- 堆结构有俩个操作:heapInsert 和 heapify
- 优先级队列结构就是 堆结构
size
i 左节点:2 * i + 1
右节点:2 * i + 2
父节点:(i-1)/ 2
维护heapsize(堆大小)
当插入一个元素,初始位置就是 当前heaspsize的位置,然后和自己的父节点比较。如果比自己的父节点大,就交换,直到根节点。如果不大,就停止。这个操作就是heapInsert
public static void heapInsert(int[] arr, int index) {
//当前值小于其父节点就停止
// 当index为0. index-1/2 也为0.也停止了。
while (arr[index] > arr[(index - 1) / 2]) {
swap(arr, index, ((index -1 ) /2));
//交换之后,更新index
index = (index - 1) /2;
}
}
当取走0位置上的数之后(获取最大值), 调整堆的结构保持 是大根堆。
最后一个数和0 交换,然后调整。调整之后,最后一个数就不在堆里了。断掉
自己的左孩子 和 右孩子 PK,挑一个最大的。 和 自己再pk.
停的条件:左右孩子都没自己大,没有左右孩子了。
public static void heapify(int[] arr, int index, int size) {
int left = 2 * index + 1; // 左孩子下标
while (left < size) { // 有左孩子,
// 获取 左孩子和右孩子 值大 的 index
int largest = left + 1 < size && arr[left + 1] > arr[left] ? left + 1 : left;
// 孩子最大 和 自己比。
largest = arr[largest] > arr[index] ? largest : index;
if (largest == index) {
// 如果自己就是最大的,退出
break;
}
// 孩子比自己大,交换
swap(arr, largest, index);
// 更新index,继续往下
index = largest;
// 更新 左孩子 下标
left = 2 * index + 1;
}
}
排序
public void userSort(int[] arr) {
if (arr == null || arr.length < 2) {
return;
}
int heapSize = arr.length;
// 插入堆,只是个大根堆,还未排序
for (int i = 0; i < arr.length; i++) {
heapInsert(arr, i);
}
// 开始调整,当前最大值在0,依次和最后的位置交换,就依次排好了。
swap(arr, 0, --heapSize);
while (heapSize > 0) {
heapify(arr, 0, heapSize);
swap(arr, 0, --heapSize);
}
}
构造堆 优化
从右到左,从下到上。
for (int i = arr.length - 1; i >= 0; i--) {
heapify(arr, i, arr.length);
}
堆排序 不如 堆结构 重要。重要的是堆结构。
一个几乎有序的数组, 每个元素移动的距离不超过k, k很小。
假设 k = 6
准备一个小根堆, size=7
遍历前7个数, 构造堆。
小根堆的最小值放在0位置。然后像右扩,
复杂度O(NlogK)
java中优先级队列就是堆。
public static void sortedArrDistanceLessK(int[] arr, int k) {
PriorityQueue<Integer> priorityQueue = new PriorityQueue<>();
int index = 0;
for (; index <= Math.min(arr.length, k); index++) {
priorityQueue.add(arr[index]);
}
int i = 0;
for (; index < arr.length; i++, index++) {
priorityQueue.add(arr[index]);
arr[i] = priorityQueue.poll();
}
while (!priorityQueue.isEmpty()) {
arr[i++] = priorityQueue.poll();
}
}
扩容,
成倍扩容,
黑盒,不能修改其中某一个数。。只能给一个数,或者取一个数,
所以需要手写堆。