1.二叉树的顺序结构
普通的二叉树是不适合用数组来存储的,因为可能会存在大量的空间浪费。而完全二叉树更适合使用顺序结 构存储。现实中我们通常把堆(一种二叉树)使用顺序结构的数组来存储,需要注意的是这里的堆和操作系统 虚拟进程地址空间中的堆是两回事,一个是数据结构,一个是操作系统中管理内存的一块区域分段。
2.堆的概念和结构
这里的堆是一种数据结构,可以分为物理结构和逻辑结构,优先级队列。
物理:数组
逻辑:完全二叉树
堆的性质:
堆可以分为大堆和小堆。
注意:大堆和小堆都不代表有序。
后面需要相应的代码调整来实现它的有序(这就是后面要讲的堆排序)。
大堆:父亲大于等于孩子
小堆:父亲小于等于孩子
3.堆的实现
3.1建堆
对于给定的一个数组,在这个数组逻辑上可以看做是一个完全二叉树,我们可以通过算法把它调整成为大堆或者小堆,建堆可以分为向上调整建堆和向下调整建堆。
以下是向上建堆建成小堆的代码示例,大堆只要改成 > 就行了。
向下调整算法有一个前提:左右子树必须是一个堆,才能调整。
以下是向下调整建堆建成小堆的代码示例,大堆只要改成 > 就行了。
3.2建堆的时间复杂度
因为堆是完全二叉树,而满二叉树也是完全二叉树。
为了简化使用满二叉树来证明(时间复杂度本来看的 就是近似值,多几个结点不影响最终结果):
以下示例用公式推导来详细介绍向下调整建堆的时间复杂度。
向下调整建堆是从最后一个非叶子结点的子树开始调整,一直调到根节点的树,就可以调整成堆。
向上调整建堆的时间复杂度是O(N*logN)
向上调整建堆的公式推导与上面类似,有兴趣的可以自己推导一番.
3.3堆的插入
3.4堆的删除
3.5堆的应用
3.5.1堆排序
堆排序就是用堆的思想来进行排序,一共分为两个步骤:
1.建堆
降序:建小堆
升序:建大堆
2.利用堆的删除思想来进行排序
建堆和堆删除中都用到了向下调整,因此掌握了向下调整,就可以完成堆排序。
3.5.2TOP - K问题
TOP-K问题:即求数据结合中前K个最大的元素或者最小的元素,一般情况下数据量都比较大。
比如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。
对于Top-K问题,能想到的最简单直接的方式就是排序,直接建成大堆或者小堆取前K个元素。
但是:如果数据量非常大,排序就不太可取了(可能 数据都不能一下子全部加载到内存中)。
最佳的方式就是用堆来解决,基本思路如下:
1. 用数据集合中前K个元素来建堆(时间复杂度O(K))
前k个元素,建小堆
前k个元素,建大堆
2. 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素
(时间复杂度O(logK*(N - K)))
将剩余N-K个元素依次与堆顶元素比完之后
堆中剩余的K个元素就是所求的前K个最小或者最大的元素。
3.总的时间复杂度O(N)
3.6堆的实现
数据结构: 手撕数据结构 - Gitee.com