一、堆排序
//堆排序
public static void heapSort(int[] arr) {
// 1. 先进行建堆
createHeap(arr);
// 2. 循环进行交换堆顶元素和最后一个元素的过程, 并且删除该元素, 进行向下调整
int heapSize = arr.length;
for (int i = 0; i < arr.length; i++) {
swap(arr, 0, heapSize - 1);
// 删除最后一个元素
heapSize--;
// 从 0 这个位置进行向下调整
shiftDown(arr, heapSize, 0);
}
}
public static void shiftDown(int[] arr, int size, int index) {
int parent = index;
int child = 2 * parent + 1;
while (child < size) {
if (child + 1 < size && arr[child + 1] > arr[child]) {
child = child + 1;
}
// 经过上面的 if 之后, child 就指向了左右子树中的较大值.
// 比较 child 和 parent 的大小
if (arr[parent] < arr[child]) {
// 不符合大堆要求
swap(arr, parent, child);
} else {
break;
}
parent = child;
child = 2 * parent + 1;
}
}
public static void createHeap(int[] arr) {
for (int i = (arr.length - 1 - 1) / 2; i >= 0; i--) {
shiftDown(arr, arr.length, i);
}
}
public static void swap(int[] arr, int x, int y) {
int tmp = arr[x];
arr[x] = arr[y];
arr[y] = tmp;
}
二、topk问题(面试题)
假设有一亿个数据,找出前 1000 个最大的数字 使用堆解决 topk 问题,有两种方案: 方案一、直接针对这一亿个数据的数组,进行建大堆 接下来循环 1000 次,进行取堆顶元素/删除堆顶元素操作 特点:得到的这前 1000 个数据是有序的 方案二、创建一个大小为 1000 的小堆,遍历这一亿个数据,依次往堆里插入 如果堆没满,直接插入 如果堆满了(小堆的堆顶元素就是这个堆里最小的元素),拿当前值和堆顶元素比较 如果当前值小于堆顶元素,就 pass 如果当前值大于堆顶元素,就删除堆顶元素,将当前值插入堆中 特点:效率更高;得到的 1000 个数据不保证顺序 海量数据处理,内存存不下,怎么办? 假设有 100 万亿个数据,内存存不下,找前 1000 个最大数据?(方案二) 将 100 万亿个数据存到磁盘上,内存中只存大小为 1000 的小堆, 每次从磁盘上读取一个数据,和堆顶元素比较并更新即可