堆与堆排序(heap sort)

893 阅读1分钟
什么是堆?

堆是一个完全二叉树的数据结构!

image.png

普通队列优先队列(堆)
从头出队列从头弹出
从尾入队列从尾插入
先进先出每次出队权值(最大值/最小值)
数组实现数组实现(数据结构上看成是堆)
堆的用处
堆怎么实现?

之前实现的最小堆可回看

首先我们要找到左右子节点和父节点的关系。 下图是当根节点为索引0时,各子节点的索引示意图

image.png

// 已知父节点parentIndex 求左右子节点
leftIndex = parentIndex * 2 + 1
rightIndex = parentIndex * 2 + 2

// 已知子节点求父节点
leftIndex or rightIndex 都看成 childIndex
parentIndex = (childIndex - 1) >> 1 // 无论左右取整后得到都是一样的

然后我们根据节点关系构建堆(一般使用大顶堆)

class MinHeap {
  constructor(compare ) {
    this.data = [];
    this.compare = compare
  }
  peek() {
    if(this.size() == 0) return null
    return this.data[0];
  }
  size() {
    return this.data.length;
  }
  push(x) {
    this.data.push(x);
    this.liftUp(this.data.length - 1);
  }
  swap(i, j) {
    [this.data[i], this.data[j]] = [this.data[j], this.data[i]];
  }
  liftUp(ind) {
    while (ind  && this.compare(this.data[ind], this.data[(ind -1) >> 1])) {
        this.swap(ind, (ind -1) >> 1);
        ind =  (ind -1) >> 1;
    }
  }
  pop() {
    if(this.size() == 0)return null
    const last = this.data.pop();
    if (this.size() != 0) {
      this.data[0] = last;
      this.liftDown(0);
    }
    return last
  }
  liftDown(ind) {
    // 先和左比
    let n = this.data.length-1;
    while (ind * 2 + 1 <= n ) {
      let tmp = ind
      if(this.compare(this.data[ind * 2 + 1] ,this.data[tmp])) tmp = ind * 2 + 1
      if(ind * 2 + 2  <= n && this.compare(this.data[ind * 2 + 2 ], this.data[tmp]))tmp = ind * 2 +2
      if(ind == tmp)break
      this.swap(ind, tmp)
      ind= tmp
    }
  }
}