堆(Heap)

作者: 张_何 | 来源:发表于2021-09-26 15:38 被阅读0次

  • 堆也是一种树状的数据结构,常见的堆实现有:
    • 二叉堆(Binary Heap, 完全二叉堆)
    • 多叉堆(D-heap、D-ary Heap)
    • 索引堆(Index Heap)
    • 二项堆(Binomial Heap)
    • 斐波那契堆(Fibonacci Heap)
    • 左倾堆(Leftist Heap, 左式堆)
    • 斜堆(Skew Heap)
  • 堆的一个重要性质: 任意节点的值总是≥或≤子节点的值
    • 如果任意节点的值总是≥子节点的值,称为:最大堆、大顶堆、大根堆
    • 如果任意节点的值总是≤子节点的值,称为:最小堆、小根堆、小顶堆
  • 由此可见堆中的元素必须具备可比较性
堆的基本接口设计
int size();
boolean isEmpty();
void clear();
void add(E element); // 添加元素
E get(); // 获得堆顶元素
E remove(); // 删除堆顶元素
E replace(E element); // 删除堆顶元素的同时插入一个新元素

二叉堆(Binary Heap)

  • 二叉堆的逻辑结构就是一颗完全二叉树,所以也叫完全二叉堆
  • 鉴于完全二叉树的一些性质,二叉堆的底层(物理结构)一般用数组实现既可
  • 索引 i 的规律(n 是元素数量)
    • 如果 i = 0, 它是根节点
    • 如果 i = 0, 它的父节点的索引为 floor((i-1)/2)
    • 如果2i + 1 ≤ n - 1, 它的左子节点的索引为 2i + 1
    • 如果 2i + 1 > n - 1, 它无左子节点
    • 如果 2i + 2 ≤ n - 1, 它的右子节点的索引为 2i + 2
    • 如果 2i + 2 > n - 1, 它无右子节点
最大堆的添加
  • 循环执行一下操作:
    • 如果node > 父节点, 与父节点交换位置
    • 如果 node ≤ 父节点,或者 node 没有父节点, 退出循环
  • 这个过程叫上滤(Sift Up), 时间复杂度为O(log)n
  • 上滤优化: 一般交换位置需要 3 行代码,可以进一步优化,将新添加节点备份,确定最终位置才摆放上去
最大堆删除
  • 用最后一个节点覆盖根节点
  • 删除最后一个节点
  • 循环执行以下操作:
    • 如果 node < 最大的子节点,与最大的子节点交换位置
    • 如果 node ≥ 最大的子节点,或者 node 没有子节点,退出循环
  • 这个过程叫做下滤,时间复杂度O(logn)
  • 同样的,交换位置的操作可以像添加那样进行优化

最大堆-批量建堆

  • 批量建堆有两种做法:
    • 自上而下的上滤
    • 自下而上的下滤
批量建堆效率对比
  • 所有节点的深度之和

    • 仅仅是叶子节点,就有近 n / 2 个,而且每一个叶子节点的深度都是O(logn)级别的
    • 因此,在叶子节点这一块,就达到了O(nlogn)级别
    • O(nlogn)的时间复杂度足以利用排序算法对所有节点进行全排序
  • 所有节点的高度之和

    • 假设是满树,节点总个数为 n,树高为 h, 那么 n = 2h - 1
    • 所有节点的树高之和 H(n) = 20 * (h - 0) + 21 * (h - 1) + 22 * (h - 2) + ... + 2h-1 * [h - (h - 1)]
    • H(n) = h * (20 + 21 + 22 + ... +2h-1) - [1 * 21 + 2 * 22 + 3 * 23 + ... + (h-1)*2h-1]
    • H(n) = h * (2h - 1) - [(h - 2) * 2h + 2]
    • H(n) = h * 2h - h - h * 2h + 2h+1 - 2
    • H(n) = 2h+1 - h -2 = 2 * (2h - 1) -h = 2n - h = 2n - log2(n+1) = O(n)
  • 公式推导

  • S(h) = 1 * 21 + 2 * 22 + 3 * 23 + ... + (h -2) * 2h-2 + (h - 1) * 2h-1
  • 2S(h) = 1 * 22 + 2 * 23 + 3 * 24 + ... + (h -2) * 2h-1 + (h - 1) * 2h
  • S(h) - 2S(h) = [21 + 22 + 23 + ... + 2h-1] - (h-1) * 2h = (2h - 2) - (h - 1) * 2h
  • S(h) = (h - 1) * 2h - (2h - 2) = (h-2)*2h + 2
  • 为什么自上而下的上滤 和 自下而上的下滤可以批量建堆成功,而自上而下的下滤和自下而上的上滤不行呢?
    其原因是不论是自上而下的上滤 还是 自下而上的下滤,每次操作后都保证的局部是大顶堆或小顶堆,而自上而下的下滤和自下而上的上滤不行
Top K 问题
  • 从 n 个整数中,找出最大前 k 个数(k 远远小于 n)
  • 如果使用排序算法进行全排序,需要O(nlogk)的时间复杂度来解决
    • 新建一个小顶堆
    • 扫描 n 个整数
      先将遍历到的前 k 个数放入堆中
      从第k + 1 个数开始,如果大于堆顶元素,就使用 replace 操作(删除堆顶元素,将第 k + 1 个数添加到堆中)
    • 扫描完毕后,堆中剩下的就是最大的前 k 个数
  • 如果是找出最小的前 k 个数呢?
    • 用大顶堆
    • 如果小于堆顶元素,就使用 replace 操作

作业

  • 了解和实现堆排序
  • 使用堆排序将一个无序数组转换成一个升序数组
    • 空间复杂度能否下降至O(1)?

相关文章

  • 堆Heap

    Heap Heap: 堆。一般也称作Priority Queue(即优先队列) 堆我们一般用一个二叉树来表示。即一...

  • heap (堆)

    堆: 说实话在仔细研究堆之前,我一直将它跟堆栈混为了一个东西。还想着这是一个后进先出的东西。我们来看一下什么是堆:...

  • Heap 堆

    两种Heap Structure: 1. Max Heap parent node比 children node大...

  • 堆:Heap

    一:堆的介绍 Heap是一种数据结构具有以下的特点:1)完全二叉树;2)heap中存储的值是偏序; Min-hea...

  • 堆 (Heap)

    “堆”这种数据结构常用在“优先级队列”的实现上, 比如Java中的PriorityQueue。今天讲讲什么是堆,如...

  • 堆(Heap)

    堆(Heap) 堆是一种常用的树形结构,是一种特殊的完全二叉树,当且仅当满足所有节点的值总是不大于或不小于其父节点...

  • 堆(heap)

    什么是堆? 堆是满足下面两个条件的一种二叉树 它是一棵完全二叉树; 堆中每个节点的值都必须大于等于(大根堆)或者小...

  • 堆 - Heap

    基本概念 堆是一种数据结构,定义为一棵完全二叉树。假如用数组储存堆结构,那么对于某个index为i的节点来说,它的...

  • 堆(heap)

    如何理解“堆”? 堆是一种特殊的树。满足两点要求。 堆是一个完全二叉树;完全二叉树要求,除了最后一次,其他层的节点...

  • 堆-Heap

    堆-Heap 堆的基本接口设计 二叉堆(最大堆) 大顶堆-添加 大顶堆-删除 删除堆顶元素的同时插入一个新元素 大...

网友评论

      本文标题:堆(Heap)

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