堆排序是一种时间复杂度O(lgn),空间复杂度O(1)的排序算法,可以自己实现堆排序,java中的PriorityQueue工具类也直接提供了实现。
自己实现堆排序
public class HeapSort {
/**
* 上浮调整
*
* @param arr
*/
public static void upAdjust(int[] arr) {
int childIndex = arr.length - 1;
int parentIndex = (childIndex - 1) / 2;
//temp保存插入的待插入的叶子节点值,用于最后的赋值
int temp = arr[childIndex];
while (childIndex > 0 && temp < arr[parentIndex]) {
arr[childIndex] = arr[parentIndex];
childIndex = parentIndex;
parentIndex = (parentIndex - 1) / 2;
}
arr[childIndex] = temp;
}
/**
* 下沉调整
*
* @param arr 待调整堆
* @param parentIndex 要下沉的父节点索引
* @param len 堆的有效大小
*/
public static void downAdjust(int[] arr, int parentIndex, int len) {
int childIndex = parentIndex * 2 + 1;
//temp保存待插入的父节点值,用于最后的赋值
int temp = arr[parentIndex];
while (childIndex < len) {
if (childIndex + 1 < len && arr[childIndex + 1] < arr[childIndex]) {
childIndex++;
}
if (temp <= arr[childIndex]) {
break;
}
arr[parentIndex] = arr[childIndex];
parentIndex = childIndex;
childIndex = childIndex * 2 + 1;
}
arr[parentIndex] = temp;
}
/**
* 构建堆
*
* @param arr
*/
public static void buildHeap(int[] arr) {
//从最后一个非叶子节点开始,依次下沉调整
for (int i = arr.length / 2 - 1; i >= 0; i--) {
downAdjust(arr, i, arr.length);
}
}
/**
* 堆排序
*
* @param arr
*/
public static void heapSort(int[] arr) {
buildHeap(arr);
for (int i = arr.length - 1; i > 0; i--) {
int temp = arr[i];
arr[i] = arr[0];
arr[0] = temp;
downAdjust(arr, 0, i);
}
}
public static void main(String[] args) {
arr = new int[]{7, 1, 3, 10, 5, 2, 8, 9, 6};
heapSort(arr);
System.out.println(Arrays.toString(arr));
}
}
PriorityQueue实现堆排序
int[] arr = new int[]{7, 1, 3, 10, 5, 2, 8, 9, 6};
PriorityQueue<Integer> queue = new PriorityQueue<Integer>((k1,k2) -> k2-k1);
for (int i : arr) {
queue.offer(i);
}
int[] res = new int[9];
int j = 0;
while (!queue.isEmpty()) {
res[j++] = queue.poll();
}
System.out.println(Arrays.toString(res));
TopK问题
问题:有n个数,找出其中最小的k个数,例如,输入[4,5,1,6,2,7,3,8],则最小的4个数是1,2,3,4
解法:
public int[] getLeastNumbers(int[] arr, int k) {
if (k == 0) {
return new int[0];
}
// 使用一个最大堆(大顶堆)
// Java 的 PriorityQueue 默认是小顶堆,添加 comparator 参数使其变成最大堆
Queue<Integer> heap = new PriorityQueue<>(k, (i1, i2) -> Integer.compare(i2, i1));
for (int e : arr) {
// 当前数字小于堆顶元素才会入堆
if (heap.isEmpty() || heap.size() < k || e < heap.peek()) {
heap.offer(e);
}
if (heap.size() > k) {
heap.poll(); // 删除堆顶最大元素
}
}
// 将堆中的元素存入数组
int[] res = new int[heap.size()];
int j = 0;
for (int e : heap) {
res[j++] = e;
}
return res;
}
参考:
1.程序员小灰《什么是二叉堆》