[golang] 数据结构-堆排序

发布时间:2020-08-11 04:50:04 作者:NicoChen
来源:网络 阅读:1303

接上文 树形选择排序
上篇也说了,树形选择排序相较简单选择排序,虽然减少了时间复杂度,但是使用了较多空间去储存每轮比较的结果,并且每次还要再和胜出节点比较。而堆排序就是为了优化这个问题而在1964年被两位大佬发明。

原理
首先有几个关于树的定义:

如果一棵树每个节点的值都大于(小于)或等于其字节点的话,那么这棵树就是大(小)根树
如果一棵大(小)根树正好又是完全二叉树,则被称为大根堆(小根堆)

堆排序就是利用大根堆(小根堆)的特性进行排序的。
从小到大排序一般用大根堆,从大到小一般用小根堆。

流程

复杂度
平均o(n*logn)
由于初次构建大根堆时有较多次的排序,所以不适合对少量元素进行排序。由于相同数值的节点在比较过程中不能保证顺序,所以是种不稳定的排序方法。

代码

package main

import (
    "fmt"
    "math/rand"
)

func main() {
    var length = 20
    var tree []int

    for i := 0; i < length; i++ {
        tree = append(tree, int(rand.Intn(1000)))
    }
    fmt.Println(tree)

    // 此时的切片o可以理解为初始状态二叉树的数(qie)组(pian)表示,然后需要将这个乱序的树调整为大根堆的状态
    // 由于是从树的右下角第一个非叶子节点开始从右向左从下往上进行比较,所以可以知道是从n/2-1这个位置的节点开始算
    for i := length/2 - 1; i >= 0; i-- {
        nodeSort(tree, i, length-1)
    }

    // 次数tree已经是个大根堆了。只需每次交换根节点和最后一个节点,并减少一个比较范围。再进行一轮比较
    for i := length - 1; i > 0; i-- {
        // 如果只剩根节点和左孩子节点,就可以提前结束了
        if i == 1 && tree[0] <= tree[i] {
            break
        }
        // 交换根节点和比较范围内最后一个节点的数值
        tree[0], tree[i] = tree[i], tree[0]
        // 这里递归的把较大值一层层提上来
        nodeSort(tree, 0, i -1)
        fmt.Println(tree)
    }
}

func nodeSort(tree []int, startNode, latestNode int) {
    var largerChild int
    leftChild := startNode*2 + 1
    rightChild := leftChild + 1

    // 子节点超过比较范围就跳出递归
    if leftChild >= latestNode {
        return
    }

    // 左右孩子节点中找到较大的,右孩子不能超出比较的范围
    if rightChild <= latestNode && tree[rightChild] > tree[leftChild] {
        largerChild = rightChild
    } else {
        largerChild = leftChild
    }

    // 此时startNode节点数值已经最大了,就不用再比下去了
    if tree[largerChild] <= tree[startNode] {
        return
    }

    // 到这里发现孩子节点数值比父节点大,所以交换位置,并继续比较子孙节点,直到把大鱼捞上来
    tree[startNode], tree[largerChild] = tree[largerChild], tree[startNode]
    nodeSort(tree, largerChild, latestNode)
}

注:代码里用递归并不是最优解

运行结果
[golang] 数据结构-堆排序

推荐阅读:
  1. App推广:如何简化流程提高效率
  2. 小程序有可能代替APP吗?

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

选择排序 go 堆排序

上一篇:浅谈Keepalived双机热备

下一篇:尝试着写自己的代码生成器

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》