美文网首页
golang 写个堆排序

golang 写个堆排序

作者: 追风骚年 | 来源:发表于2021-01-25 16:57 被阅读0次

堆排序是我觉得排序里面数据结构运用最灵活的一个算法,首先如何用一个数组表示一个堆,如何取到节点的父节点和左右子节点。

10.png

左侧是一个堆,右侧是一个数组的索引,可见我们只要从上到下,从左到右填充数字,并且保证,所有父节点大于两个子节点就可以构成一个堆。

对于一个堆,我们可以通过父节点和子节点之间的索引总结出如下关系:

// func heap(i int) {
//  parent := (i - 1) / 2   // 父节点
//  c1 := 2*i + 1          // 左子节点
//  c2 := 2*i + 2          // 右子节点
// }

算法描述

  • 将初始待排序关键字序列(R1,R2….Rn)构建成大顶堆,此堆为初始的无序区;
  • 将堆顶元素R[1]与最后一个元素R[n]交换,此时得到新的无序区(R1,R2,……Rn-1)和新的有序区(Rn),且满足R[1,2…n-1]<=R[n];
  • 由于交换后新的堆顶R[1]可能违反堆的性质,因此需要对当前无序区(R1,R2,……Rn-1)调整为新堆,然后再次将R[1]与无序区最后一个元素交换,得到新的无序区(R1,R2….Rn-2)和新的有序区(Rn-1,Rn)。不断重复此过程直到有序区的元素个数为n-1,则整个排序过程完成。

上代码

// 保证父节点大于两个子节点
func heapify(tree []int, n, i int) {
    if i >= n {
        return
    }
    c1 := 2*i + 1 // 左子节点
    c2 := 2*i + 2 // 右子节点

    max := i // 默认最大节点是当前节点
    if c1 < n && tree[c1] > tree[max] {
        // 最大节点是左节点
        max = c1
    }
    if c2 < n && tree[c2] > tree[max] {
        // 最大节点是右节点
        max = c2
    }

    // 如果最大节点不是当前节点
    if max != i {
        // 交换最大节点和子节点
        tree[max], tree[i] = tree[i], tree[max]
        // 对子节点重新堆化
        heapify(tree, n, max)
    }
}

// 数组建堆
func buildHeap(tree []int, n int) {
    lastNode := n - 1            // 最后一个节点
    parent := (lastNode - 1) / 2 // 最后一个节点的父节点
    for i := parent; i >= 0; i-- {
        heapify(tree, n, i)
    }
}

func heapSort(tree []int, n int) {
    buildHeap(tree, n) // 建堆
    fmt.Println(tree)
    for i := n - 1; i >= 0; i-- {
        // 0 为堆顶元素  必定是最大
        tree[i], tree[0] = tree[0], tree[i]
        heapify(tree, i, 0) // 继续堆化
    }
}

func TestHeapify(t *testing.T) {
    tree := rand.Perm(10)
    t.Log(tree)
    heapSort(tree, len(tree))
    t.Log(tree)
}

小结

堆排序我在理解过程中,很容易犯一个错误,以为通过中序遍历就可以拿到一个有序数组,其实不然,堆只是保证了父节点大于两个子节点,并没有保证子节点之间的一个大小关系,没有保证左子树和右子树的大小关系。

9.png

通过这个例子就很好理解,但是可见根节点是最大元素,根节点比各个子节点,以及子节点的父节点都要大。

参考文档

相关文章

  • golang 写个堆排序

    堆排序是我觉得排序里面数据结构运用最灵活的一个算法,首先如何用一个数组表示一个堆,如何取到节点的父节点和左右子节点...

  • golang 写个冒泡

    在算法这个领域,大学的课程也都是从冒泡排序开始的,今天用 golang 写个简单的冒泡排序。 这实在有点简单,特别...

  • golang版堆排序

  • 堆排序(golang实现)

    封装成函数: 测试: 输出:[9 0 6 5 8 2 1 7 4 3][0 1 2 3 4 5 6 7 8 9]

  • golang实现堆排序

    算法题:给定一个整型数组,将数组的中的元素按升序排序。 基本思路:操作:排序输入:无序整型数组输出:有序整型数组 ...

  • golang版 堆排序

    核心代码 调用入口

  • golang + goquery写个爬虫

    goquery 是一个超好用的库,可以帮你爬取页面,解析页面。我用它写了个糗事百科的爬虫,可以用来看当前有什么好玩...

  • golang 写个希尔排序

    希尔排序非常的牛,听说是第一个打破时间复杂度我 n² 的算法,通过一个区间不断缩小,由远及近,最终达到有序状态,也...

  • golang 写个快速排序

    快速排序是大多数语言内置 sort 函数的默认实现方式,简单可分为两路排序和三路排序,我在相关资料中,发现两路排序...

  • golang 写个选择排序

    先看选择排序定义。 初始状态:无序区为R[1..n],有序区为空; 第i趟排序(i=1,2,3…n-1)开始时,当...

网友评论

      本文标题:golang 写个堆排序

      本文链接:https://www.haomeiwen.com/subject/mrkizktx.html