堆
**堆序性质:**和普通的树不同的是,堆具有堆序性质。所谓堆序性质,即堆的根节点要比所有字节点大,并且递归地具有此性质。即树根比左孩子和右孩子要大,同时左孩子在左子树中最大,右孩子在右子树中最大。
**结构性质:**类似完全二叉树,底层上的元素被全部填满,底层从左往右填入元素。
二叉堆
二叉堆即每个节点最多只有两个节点的堆结构,每个节点(序号i)的父节点,左子节点,右子节点具有如下的变换关系
- 父节点: ⌊ i / 2 ⌋ \left \lfloor i/2 \right \rfloor ⌊i/2⌋
- 左子节点: 2 i + 1 2i+1 2i+1
- 右子节点: 2 i + 2 2i+2 2i+2
堆操作
**上滤:**将某个节点和父节点进行比较,如果比父节点大,则和父节点进行交换,并且父节点也递归地进行这个过程。
**下滤:**将某个节点和它的子节点进行比较,选出最大的节点和自己进行交换。被交换的节点迭代地进行这个过程。
**插入:**为了满足结构性质,从数组的末端插入,然后利用上滤维护堆序性质
**弹出:**获取最小值,把根节点弹出并且删除,然后将末尾元素放置于根节点位置,然后用下滤维护堆序性质。
建堆
**思路1:**基于下滤操作。循环地,从 ⌊ n / 2 ⌋ \left \lfloor n/2 \right \rfloor ⌊n/2⌋到0,每个节点执行下滤操作。每次下滤操作的时间复杂度是 l o g ( n ) log(n) log(n)(树的高度),一共执行n/2次,因此时间复杂度是 n l o g ( n ) nlog(n) nlog(n)
**思路2:**基于上滤操作。将一个数组的1到n-1元素i,不断地执行插入操作。每次插入的时间复杂度同样是 l o g ( n ) log(n) log(n),一共执行n-1次,因此时间复杂度同样是 n l o g ( n ) nlog(n) nlog(n)
堆排序
基于最大堆的堆排序过程如下:
- 建堆
- 交换堆头和堆尾
- 堆大小减一
- 下滤