前言
算法就是枯燥无味的,需要自己耐心去学习。
堆排序是什么?
一个不断调整堆的排序算法。
堆排序的应用场景
1、使用于数据量很大的情况。比如找出1000w数据中最小的前100个数字。建立一百个节点的大顶堆,首先将前一百个数放入堆中,之后每放入一个数就删除一个堆顶元素,最后剩下的就是最小的100个数。
与其他排序算法相比
1、数据量比较小的时候,选择排序是最快的。
2、当不仅仅需要排序,而是要取一个数据比较多的数组中的前n个数,可以考虑使用堆排序。
堆排序流程图
1、将无序数组构建成一个堆,根据升序需求选择大顶堆;
2、将堆顶元素与末尾元素交换,将最大元素"沉"到数组末端;
3、重新调整结构,使其满足堆定义,然后继续交换堆顶元素与当前末尾元素,反复执行调整+交换步骤,直到整个序列有序。
源码
public class Solution {
public static void main(String[] args) {
int[] arr = {2, 1, 5, 4, 6, 3, 7};
sortHeap(arr);
showArr(arr);
}
/**
* 建立大顶堆。从倒数第二层最右边的父节点开始调整堆。
* len并不总是数组的真实长度,而是你想调整的数组的长度。
*/
public static void buildMaxHeap(int[] arr, int len) {
int last = len - 1;
int parent = (last - 1) / 2;
for (int i = parent; i >= 0; i--) {
heapify(arr, len, i);
}
}
/**
* 调整为二叉堆
*
* len并不总是数组的真实长度,而是你想调整的数组的长度。
*
* 易错点:两个if语句,必须写max而不是写parent。因为要确认左右子树与根的关系
*
*/
public static void heapify(int[] arr, int len, int parent) {
int left = parent * 2 + 1;
int right = parent * 2 + 2;
int max = parent;
if (left < len && arr[left] > arr[max]) {
max = left;
}
if (right < len && arr[right] > arr[max]) {
max = right;
}
if (max != parent) {
swap(arr, max, parent);
heapify(arr, len, max); //堆调整之后,子节点可能也需要调整。
}
}
/**
* 对堆进行排序。首先将第一个顶点输出,将第一个节点与最后一个节点交换,然后调整堆
*/
public static void sortHeap(int[] arr){
buildMaxHeap(arr,arr.length);
for (int i = arr.length-1; i >=0; i--) {
swap(arr,0,i);
//建立堆:数组以及数组需要调整的长度。因为放在后面的最大元素我是不想再动的
buildMaxHeap(arr,i);
}
}
public static void swap(int[] arr, int a, int b) {
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
public static void showArr(int[] arr) {
for (int value : arr) {
System.out.print(value + " ");
}
System.out.println();
}
}