前言
知识它忘得太快了,而自己又处于过五关斩六将的状态,冲啊~
思路
堆排序很经典,这里不追求赘述堆的相关知识点,而是视作已经堆结构有一定了解
- 堆是一种完全二叉树的结构,分为大顶堆和小顶堆,大顶堆就是父节点的值比左右子结点的值大,小顶堆则相反
- 堆排序的时间复杂度是
O(n*log2n)
,最好最坏都是这个 - 堆排序(排序结果从小到大)分为两步,第一步是把给定的一个数组初始化为一个大顶堆,第二步是将第一个元素与最后一个元素交换,因为第一个元素一定是最大的,之后再次进行大顶堆的调整,交换,调整……………………,最后将得到一个升序队列。
Java 实现
class Solution {
public int[] sortArray(int[] nums) {
heapSort(nums);
return nums;
}
// 堆排序
public void heapSort(int[] nums){
// 初始建堆
for(int i= nums.length/2;i>=0;i--){
HeapAdjust(nums,i,nums.length);
}
// 进行n-1次循环,每次循环完,0下标位置就是最大的元素,我们把该元素放到数组末尾
for(int i = nums.length-1;i>0;i--){
int t = nums[i];
nums[i] = nums[0];
nums[0] = t;
HeapAdjust(nums,0,i);
}
}
public void HeapAdjust(int[] nums,int parent,int len){
// 保存当前父节点的值
int parentValue = nums[parent];
// 找到左节点
int childIndex = 2 * parent +1;
while(childIndex<len){
// 如果有右节点,并且大小是比左节点大的,那么选取右节点,后续会跟父节点进行比较
if(childIndex+1<len && nums[childIndex]<nums[childIndex+1]){
childIndex++;// 此时index为右结点
}
// 如果此时父结点已经比孩子结点都大,直接跳出即可,根本不需要交换,那么后面也不会有下沉情况
if(parentValue>nums[childIndex]) break;
// 否则进行交换
nums[parent] = nums[childIndex];
nums[childIndex] = parentValue;
// 交换完之后,进行一个"下沉"操作
parent = childIndex;
childIndex = parent * 2 + 1;
}
}
}