排序算法及实现 - 堆排序

堆排序

参考:
https://www.cnblogs.com/chengxiao/p/6129630.html
https://blog.csdn.net/qq_34374664/article/details/79545940
https://www.cnblogs.com/wengshuhang/articles/10039476.html

堆分为最大堆和最小堆,其实就是完全二叉树。
最大堆要求节点的元素都要不小于其孩子;
最小堆要求节点元素都不大于其左右孩子;
两者对左右孩子的大小关系不做任何要求,其实很好理解。有了上面的定义,我们可以得知,处于最大堆的根节点的元素一定是这个堆中的最大值。

其实我们的堆排序算法就是抓住了堆的这一特点,每次都取堆顶的元素,将其放在序列最后面,然后将剩余的元素重新调整为最大堆,依次类推,最终得到排序的序列。

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

在这里插入图片描述

package main

import(
        "fmt"
)

// 构建堆
func build_heap(data_list []int, i int, length int){
        tmp := data_list[i] // 子树的root节点
        for k := i * 2 + 1; k < length; k = k * 2 + 1{
                if (k + 1 < length) && (data_list[k] < data_list[k+1]) {//右子树的游标比数组长度小,并且左子树小于右子树,让游标指向右子树
                        k++
                }
                if data_list[k] > tmp { //右子树大于root节点,调整,让root游标指向新的root节点
                        data_list[i] = data_list[k]
                        i = k
                } else {
                        break
                }
        }
        data_list[i] = tmp  
}

// 排序
func sort(data_list []int) {
        for i := len(data_list)/2 - 1; i >= 0; i-- {// 遍历数组中,子树的个数
                build_heap(data_list, i, len(data_list))
        }
        for j := len(data_list) - 1; j > 0; j-- {//	遍历数组
                swap(data_list, 0, j)
                build_heap(data_list, 0, j)
        }
}

// 交换
func swap(data_list []int, a int, b int){
        tmp := data_list[a]
        data_list[a] = data_list[b]
        data_list[b] = tmp
}

func main() {
        fmt.Println("=== 排序算法 - 堆排序 ===")
        data_list := []int{19, 8, 3, 5, 7, 3, 2, 11}
        sort(data_list)
        for i := 0; i < len(data_list); i++ {
                fmt.Printf("%d ", data_list[i])
        }
        // fmt.Println(data_list) //go支持直接遍历数组打印
        fmt.Println("")
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值