前置知识
完全二叉树:
如果一棵深度为K二叉树,1至k-1层的结点都是满的,即每一层节点都满足2 ^(i-1), 只有最下面的一层的结点数小于或等于2 ^(i-1),并且最下面一层的结点都集中在该层最左边的若干位置,则此二叉树称为完全二叉树。
简单来说:
- 完全二又树只允许最后一行不为满
- 且最后一行必须从左往右排序
- 最后一行元素之间不可以有间隔
堆
堆的定义
堆的数据结构是完全二叉树或一堆数组,因为堆在逻辑上是一棵完全二叉树,在物理结构上是一个一维数组。
堆结构是一种数组对象,它可以被视为一棵完全二叉树。
堆是非线性数据结构,相当于一维数组,有两个直接后继。
树中每个结点与数组中存放该结点中值的那个元素相对应,如下图:
堆的性质
1、 结点性质(结构性)
设数组A的长度为len,堆的结点个数为size,size≤len,则A[存储编号为i的结点值(1<i<size),堆的根为A[1],并且利用完全二叉树的性质,我们很容易求第i个结点的父结点的下标为i/2,左孩子结点的下标为2i,右孩子结点的下标为2i+1;
注意:数组下标与实际差1。
2、堆序性
对除根以外的每个结点i,A[parent(i)]>A[i]。即除根结点以外所有结点的值都不得超过其父结点的值,这种堆又称为“大根堆”,这样就推出,堆中的最大元素存放在根结点中,且每一结点的子树中的结点值都小于等于该结点的值。
反之,对除根以外的每个结点i,A[parent(i)]≤A[i]的堆,称为“小根堆”。
堆的操作
下滤(删除):
下滤操作通常用于删除堆中的元素。具体步骤如下:
- 删除根结点,根结点为空,视为当前结点位置p。
- 比较p的左右结点的大小,把较大的子节点与p交换(对于大根堆)。
- 重复步骤2,直到p大于或等于其子节点,或者位于叶子节点。
时间复杂度:o(logN)
上滤(插入):
上滤操作通常用于向堆中插入新元素。具体步骤如下:
- 将新元素插入到堆的末尾。
- 如果新元素比其父节点大(对于大根堆),则将其与父节点交换。
- 重复步骤2,直到新元素小于或等于其父节点,或者新元素位于根节点
时间复杂度:o(logN)
建堆法
自顶而下建堆
自顶而下建堆的方法是从根节点开始逐步向下构建。
对应上滤。
将元素一个一个插入到堆内:将新元素放入到堆的 最后一位,对其进行上滤操作。再放入新元素。时间复杂度:O(NlogN)。
以小根堆为例:
自下而上建堆
对应下滤。
给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆。
先把元素调整成堆,再对父节点进行下滤操作,直到根节点操作完毕。
具体操作:从最后一个非叶子节点开始,依次对每个节点进行下滤操作,直到根节点操作完毕