一、什么是堆排序
堆,是一种特殊的树,一般有两种情况,第一种是最大堆,也就是最大的元素在堆顶;第二种是最小堆,最小的在堆顶。(我们写的是最大堆)
堆排序有几个显著的优势:
- 时间复杂度稳定:堆排序的时间复杂度为O(n log n),在平均和最坏情况下都保持不变。
- 原地排序:堆排序是原地排序算法,它只需要常数级别的额外空间(除了输入数组本身),这对于内存受限的环境非常有利。
- 灵活性:堆排序既可以用于最大堆也可以用于最小堆,根据需要可以灵活调整排序顺序。
思路:
- 首先,既然堆是一种树,那么我们需要知道它的深度,如果我们自己画图或者互联网检索,就会发现,堆的深度为 (总大小 / 2 - 1)
- 其次,我们需要知道左节点和右节点的位置,假设我们的堆顶为i,则分别是 2 * i + 1,2 * i + 2
- 知道这些的用处是,我们将从堆底开始,每三个为一组,这样子遍历,找出最大的,作为这三个数组成的树的顶端,不断循环,直到,堆顶为最大的树
二、代码实现
话不多说,上代码
/ heapSort 将最大的数放在第一位,也就是堆顶
func heapSort(arr []int, length int) {
if arr == nil || length < 2 {
return
}
// 堆是一种特殊的树
// 获取堆的深度
depth := length/2 - 1
// 让循环从堆的最下面开始循环
//保证三个数组成的树顶的值是最顶端及它的两个子节点中最大的
for i := depth; i >= 0; i-- {
topMax := i
leftChild := 2*i + 1
rightChild := 2*i + 2
if leftChild < length && arr[leftChild] > arr[topMax] {
topMax = leftChild
}
if rightChild < length && arr[rightChild] > arr[topMax] {
topMax = rightChild
}
if topMax != i {
arr[i], arr[topMax] = arr[topMax], arr[i]
}
}
}
堆排序的应用就在于快速的找到最大的元素,或者可以考虑递归堆化,来实现可以输出从小到大的顺序