1.堆
- 完全二叉树:
数组表示时,使用下标为0的位置时,左孩子的下标 2*i + 1,右孩子 2*i + 2, 父节点 (i-1)/2, i为节点所在层数
数组表示,不适用下标为0的位置时,lchild: 2*i , rchild: 2*i+1, 父节点: i/2,此时可以用位运算代替*/运算
用数组表示时,可以规定完全二叉树的最大节点数size,那么在数组 [0,size-1] 的下标范围,都为该完全二叉树的节点范围
- 最大堆/大根堆:
任何一个子树的最大的节点都为该子树的头节点
- 最小堆/小根堆:
任何一个子树的最小的节点都为该子树的头节点
- 堆排序:
- 先让整个数组变成最大堆,建堆的过程:从上到下-> O(N*logN) ; 从下到上-> O(N)
- 把堆的最大值和末尾值交换,然后减少堆的大小之后再去调整堆,重复此过程直至完成所有值的调整,时间复杂度O(N*logN)
- java中的PriorityQueue就是用堆实现的,默认使用最小堆,可以传入比较器修改
当传入复杂数据时,如果修改了数据的某属性需要重新排序,java的PriorityQueue是不支持的,所以需要重新实现该结构,在堆结构中实现resign方法实现重排序,实现代码参见 相关示例代码 中的ComparatorHeap类的实现
2.堆相关习题
- 已知一个几乎有序的数组,几乎有序是指,如果把数组排好顺序的话,每个元素移动的距离一定不超过k,并且k相对于数组长度来说是比较小的。请选择一个合适的排序策略,对这个数组进行排序。
- 使用小根堆,堆的大小为k + 1,先向heap中添加值保证heap大小为k+1,然后弹出最小值,重复此过程直到arr中已没有数据可以向heap中添加时,依次弹出堆中剩下的数据即可,时间复杂度 O(N * logk)