- 堆结构是用数组实现的完全二叉树结构
- 完全二叉树 中 如果 每颗子树的最大值在顶部, 就是大根堆
- 完全二叉树 中 如果 每颗子树的最小值在顶部, 就是小根堆
- 堆结构有俩个操作: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(); } }
扩容,
成倍扩容,
黑盒,不能修改其中某一个数。。只能给一个数,或者取一个数,
所以需要手写堆。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统