堆的特点就是堆顶的元素是一个最值,大顶堆的堆顶是最大值,小顶堆则是最小值。
堆排序就是把堆顶的元素与最后一个元素交换,交换之后破坏了堆的特性,我们再把堆中剩余的元素再次构成一个大顶堆,然后再把堆顶元素与最后第二个元素交换….如此往复下去,等到剩余的元素只有一个的时候,此时的数组就是有序的了。
代码:
//堆排序
func headSort(arr []int) {
n := len(arr)
//构建大顶堆
for i := (n - 2) / 2; i >= 0; i-- {
downAdjust(arr, i, n-1)
}
//进行堆排序
for i := n - 1; i >= 1; i-- {
// 把堆顶元素与最后一个元素交换
temp := arr[i]
arr[i] = arr[0]
arr[0] = temp
// 把打乱的堆进行调整,恢复堆的特性
downAdjust(arr, 0, i-1)
}
}
//下沉操作
func downAdjust(arr []int, parent int, n int) {
//临时保存要下沉的元
temp := arr[parent]
//定位左孩子节点的位置
child := 2*parent + 1
//开始下沉
for {
if child > n {
break
}
// 如果右孩子节点比左孩子大,则定位到右孩子
if child+1 <= n && arr[child]> arr[child+1]{
child++
}
// 如果孩子节点小于或等于父节点,则下沉结束
if arr[child]>= temp{
break
}
// 父节点进行下沉
arr[parent] = arr[child]
parent = child
child = 2*parent + 1
}
arr[parent] = temp
}
性质:1、时间复杂度:O(nlogn) 2、空间复杂度:O(1) 3、非稳定排序 4、原地排序