之前我们了解过最大堆和最小堆
我们知道最大堆的根节点上是数组的最大值,但是子节点的顺序指服从,子节点小于父节点,并没有严格的像二叉搜索树一般
那么今天要说的堆排序就是利用了最大堆和最小堆根的性质所设计的一种排序算法
-
最大堆:每个节点的值都大于或等于其子节点的值,在堆排序算法中用于升序排列;
-
最小堆:每个节点的值都小于或等于其子节点的值,在堆排序算法中用于降序排列
平均时间复杂度:O(NlogN)
算法步骤:
-
由数组建堆(最大堆或最小堆)
-
将堆的根节点和最右叶子节点交换位置做一个伪删除
-
重建堆
-
反复以上步骤,直到完成排序,最大堆的最小元素上滤到根节点,最小堆的最大元素上滤到根节点
堆排序代码实现:
public class HeapSort {
/**
* 堆排序:
* - 建堆
* - 删除堆顶
* - 循环以上两步
* @param arr
*/
public void heapSort(int[] arr){
int len = arr.length;
//构造最大堆
buildMaxHeap(arr, len);
while(len > 1){
//取出最大值放于叶子节点,将叶子节点放于根节点
swap(arr,0,len-1);
//数组长度-1(相当于移除)
len--;
//移除了最大值后继续构建最大堆
heapify(arr,0,len);
}
}
/**
* 构建最大堆
* @param arr
* @param len
*/
private void buildMaxHeap(int[] arr, int len) {
for (int i = (int) Math.floor(len / 2); i >= 0; i--) {
heapify(arr, i, len);
}
}
/**
* 建堆
* @param arr
* @param i
* @param 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);
}
}
/**
* 交换函数
* @param array
* @param i
* @param j
*/
private static void swap(int[] array,int i ,int j){
int temp = array[i];
array[i] = array[j];
array[j] = temp;
}
public static void main(String[] args) {
HeapSort heapSort = new HeapSort();
int[] a = new int[]{1,2,5,1,2,7,3,5,42,2};
heapSort.heapSort(a);
for(int i : a){
System.out.println(i);
}
}
}
来源:https://blog.csdn.net/weixin_41922289/article/details/99881643