堆排序
将数组看成一个二叉堆,大致就是这样的
父节点要大于子节点
简单一点,遍历整个树,每个节点都和父节点比较,如果大于父节点,则交换位置
tailrec fun casWithFather(array: IntArray, index: Int) {
if (index == 0) {
//第一个节点 do nothing
} else {
//和父节点比,如果大于父节点,递归和父节点比。
val parent = (index + 1) / 2 - 1
if (array[parent] < array[index]) {
array.swap(index, parent)
casWithFather(array, parent)
}
}
}
最大堆排序
经过上一步的处理,这个堆已经满足了父节点大于子节点,为一个最大堆。
如何来利用最大堆排序呢,我们取出最大的父节点,然后再生成最大堆。
- 取出最大父节点
- 与最尾端节点交换位置
- 对新的堆排序(排除掉取出放在尾端的节点)
tailrec fun casWithChild(array: IntArray, farther: Int, end: Int) {
val lc = farther * 2 + 1 //左节点
val rc = farther * 2 + 2 //右节点
if (lc >= end) {//到达了需要排序"堆"的终点
return
}
val better = if (rc >= end || array[lc] > array[rc]) {
lc
} else {
rc
}
if (array[farther] < array[better]) {
array.swap(farther, better)
casWithChild(array, better, end)
}
}
完整调用
fun sort(array: IntArray) {
for (i in 0..array.size - 1) {
casWithFather(array, i)
} //所有子节点都比父节点小
for (i in (1..array.size - 1).reversed()) {//从尾端开始往前推
array.swap(0, i)//把最大的0节点与该节点交换
//再次从0开始排序,但是这个堆到i就结束了
//因为i是上一步交换过来的已排序好的节点
casWithChild(array, 0, i)
}
}