前端算法之路-堆

318 阅读2分钟

完全二叉树

  • 在完全二叉树中,除了最底层节点可能没填满外,其余每层节点数都达到最大值,并且最下面一层的节点都集中在该层最左边的若干位置。若最底层为第 h 层,则该层包含 1~ 2^h -1 个节点

image.png

image.png

定义

  • 堆是一种非线性结构,可以把堆看作一个数组,也可以被看作一个完全二叉树,通俗来讲堆其实就是利用完全二叉树的结构来维护的一维数组

image.png

image.png

分类

  • 大顶堆
    • 每个结点的值都大于或等于其左右孩子结点的值
  • 小顶堆
    • 每个结点的值都小于或等于其左右孩子结点的值

image.png

构建顶堆

  • 交换
//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个元素的次小值,如此反复执行,便能得到一个有序序列了,建立最大堆时是从最后一个非叶子节点开始从下往上调整的