堆
完全二叉树
- 在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^h -1 个节点
定义
- 堆是一种非线性结构,可以把堆看作一个数组,也可以被看作一个完全二叉树,通俗来讲堆其实就是利用完全二叉树的结构来维护的一维数组
分类
- 大顶堆
- 每个结点的值都大于或等于其左右孩子结点的值
- 小顶堆
- 每个结点的值都小于或等于其左右孩子结点的值
构建顶堆
- 交换
//heap为数据,a,b为交换节点的下标
function swap(heap,a,b){
[heap[a],heap[b]]=[heap[b],heap[a]]
}
- 上浮(自下而上堆化)
//heap为想要堆排序的数组,idx为最后一个非叶子节点
function up(heap,idx){
const parentIdx = (idx-1)/2|0;
if(parentIdx >=0 && heap[parentIdx] < heap[idx]){ //如果父节点的值小于子节点
swap( heap , parentIdx , idx ) //交换两节点的值
up( heap , parentIdx ) //继续递归调整
}
}
- 下沉(自上而下堆化)
//最后一个非叶子节点-idx为最后一个叶子节点
function down(heap,idx){
let left=2*idx+1; //idx的左子节点
let right=2*idx+2;//idx的右子节点
let max=idx;
if(left<heap.length&&heap[left]>heap[max]){ //比较出最大值,更新max
max=left;
}
if(right<heap.length&&heap[right]>heap[max]){ //比较出最大值,更新max
max=right;
}
if(max!==idx){ //如果max和idx不同
swap(heap,max,idx) //交换idx和max的值
down(heap,max) //继续递归调整
}
}
应用-堆排序
- 排序方式
- 升序-大顶堆
- 每个结点的值都大于或等于其左右孩子结点的值,我们把大顶堆构建完毕后根节点的值一定是最大的,然后把根节点的和最后一个元素(也可以说最后一个节点)交换位置,那么末尾元素此时就是最大元素了
- 降序-小顶堆
- 每个结点的值都小于或等于其左右孩子结点的值,我们把小顶堆构建完毕后根节点的值一定是最小的,然后把根节点的和最后一个元素(也可以说最后一个节点)交换位置,那么末尾元素此时就是最小元素了
- 升序-大顶堆
- 基本思想
- 将待排序序列构造成一个大顶堆,此时,整个序列的最大值就是堆顶的根节点。将其与末尾元素进行交换,此时末尾就为最大值。然后将剩余n-1个元素重新构造成一个堆,这样会得到n个元素的次小值,如此反复执行,便能得到一个有序序列了,建立最大堆时是从最后一个非叶子节点开始从下往上调整的