You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2.4 KiB

堆排序

  • 介绍
    • 定义
      • 堆是一种特殊的完全二叉树结构
        • 大根堆:一棵完全二叉树满足任意节点的值都比孩子结点大
        • 小根堆:一棵完全二叉树满足任意节点的值都比孩子结点小
      • 堆的向下调整性质
        • 目的其实就是一个排序的过程
        • 体现通过向下调整实现获得大根堆
        • 总结当根节点的左右子树都是堆时,但是根不满足堆,可以通过一次向下的调整来将其变换成一个堆。
    • 复杂度O(n log(n))
    • 思路: 通过建立堆,并重复使用向下调整的性质进行数据排序。
    • 过程:
      • 1建立堆
      • 2得到堆顶元素为最大元素
      • 3去除堆顶,将堆最后元素(原因是保证堆成立)放到堆顶,此时可以通过一次调整重新是堆有序.
      • 4堆顶元素为第二大元素
      • 5 可以重复3直到堆变空
    • 关键字:
      • 构建堆(农村包围城市)
      • 向下排序
      • 实现排序:完全二叉树 >> 向下调整 > 输出元素
    • 存在问题
      • 在快的排序算法在相对较慢
      • 快速排序 > 归并排序 > 堆排序
    • 应用
      • 实现解决top-K问题
        • top-K对比
          • 排序后切片 O(n log(n))
          • 排序LowB三人组 O(kn)
          • 堆排序思路 O(n log(k))
  • 原理
  • 代码

/**
Heap 进行排序
	1. 建堆
	2. 交换值并向下调整
 */
func Heap(li []int) []int {
	n := len(li)
	for i := (n-2) / 2; i >= 0; i-- { // 创建堆
		sift(li, i, n - 1)
	}

	for i := n - 1; i >= 0; i-- { // 先做交换(减少内存)后做向下调整
		li[0], li[i] = li[i], li[0]
		sift(li, 0, i - 1)
	}
	return li
}

/**
sift 向下调整
	li 数组列表
	low 堆的根节点的下标
	high 堆的最后一个元素的下标
 */
func sift(li []int, low, high int)  {
	/**
	i 指一层中的根
	j 开始是左孩子
	t 指一层中某个需要调整的值
	 */
	i, j, t := low, 2 * low + 1, li[low]
	for j <= high { // 在范围内进行循环,防止越界
		 if j + 1 <= high && li[j+1] > li[j] { // 比较一个根下的两个孩子大小,取大值的位置
			j = j + 1
		 }
		 if li[j] > t { // 与指定根值比较,若值比根大,继续循环
		 	li[i], i, j = li[j], j, 2 * i + 1
		 } else {
			 // li[i] = t // 将临时值放回,移至循环结束位置
			 break
		 }
	}
	li[i] = t // 将临时值放回

}