堆排序算法总结
堆排序的用途很广泛,在面试中也是一个经常会被通过各种角度考到的点:
- 从1亿个数据里面挑选最大的k个数?
- 求无序数组的中位数,求第k大数?
- 等等。。。
堆排序的实现
分为两步:
- 构建堆
- 排序
1.首先是构建堆
1.1通过JDK工具类构建堆
构建堆可以自己实现,也可以通过JDk中相应的实现PriorityQueue,PriorityQueue默认是最小堆,如果想要实现最大堆的话,我们可以在初始化时添加一个Comparator比较器,如:
PriorityQueue pq = new PriorityQueue(new Comparator() {
@Override
public int compare(Integer o1, Integer o2) {
return o2-o1;
}
});何时选择最大堆?何时选择最小堆?
一般来说,当要对数组进行升序排序时,选择最大堆;反之,选择最小堆。
1.2 自己实现构建堆
代码一:
//摘抄自菜鸟教程:https://www.runoob.com/w3cnote/heap-sort.html
private void buildMaxHeap(int[] arr, int len) {
for (int i = (int) Math.floor(len / 2); i >= 0; i--) {
heapify(arr, i, len);
}
}
private void heapify(int[] arr, int i, int len) {
int left = 2 * i + 1;
int right = 2 * i + 2;
int largest = i;
if (left < len && arr[left] > arr[largest]) {
largest = left;
}
if (right < len && arr[right] > arr[largest]) {
largest = right;
}
if (largest != i) {
swap(arr, i, largest);
heapify(arr, largest, len);
}
}
private void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}代码二:
static void buildSmallHeap(int[] a){
for (int i = a.length/2; i >=0 ; i--) {
sink(a,i,a.length);
}
}
//参考priorityQueue中的方法shiftDown方法
static void sink(int[] a,int k,int len){
int key = a[k];
int half = len>>>1;
while (k<half){
int child = (k<<1) + 1;//左孩子
int c = a[child];
int right = child + 1;//右孩子
if(right < len && c > a[right])c = a[child = right];//右孩子小于左孩子,对child、c重新赋值
if(key < a[child]) break;//父节点均小于左右孩子,直接结束
a[k] = c;
k = child;
}
a[k] = key;
}现在我们来分析一下构建堆的时间复杂度:
https://www.cnblogs.com/wongyi/p/7685061.html
https://www.zhihu.com/question/20729324

