什么是堆?
堆是一个完全二叉树的数据结构!
普通队列 | 优先队列(堆) |
---|---|
从头出队列 | 从头弹出 |
从尾入队列 | 从尾插入 |
先进先出 | 每次出队权值(最大值/最小值) |
数组实现 | 数组实现(数据结构上看成是堆) |
堆的用处
堆怎么实现?
之前实现的最小堆可回看
首先我们要找到左右子节点和父节点的关系。
下图是当根节点为编号0时,各子节点的编号示意图
// 已知父节点parentIndex 求左右子节点
leftIndex = parentIndex * 2 + 1
rightIndex = parentIndex * 2 + 2
// 已知子节点求父节点
leftIndex or rightIndex 都看成 childIndex
parentIndex = (childIndex - 1) >> 1 // 无论左右取整后得到都是一样的
复制代码
然后我们根据节点关系构建堆(一般使用大顶堆)
class Heap{
constructor(){
this.data = [] //初始化数组存储
this.cnt = 0 // 长度
}
//
size(){
return this.cnt
}
// 顶部元素
top(){
if(this.size()==0)return -1
return this.data[0]
}
swap(i,j){
[this.data[i], this.data[j]] =[this.data[j], this.data[i]]
}
// 插入元素
push(val){
this.data[this.cnt ++] = val
this.liftUp(this.cnt-1) //向上调整
}
//
liftUp(ind){
// 和父节点做比较 , 如果比父节点大就和父节点交换位置
let parentIndex = (ind - 1) >> 1
while(ind && this.data[ind] > this.data[parentIndex]){
parentIndex = (ind - 1) >> 1
this.swap(ind, parentIndex)
ind = parentIndex
}
}
// 弹出元素
pop(){
this.data[0] = this.data.pop() // 将末尾元素放到头部来 向下调整
// 如果需要堆排序 直接将上面代码改为
// this.swap(0, cnt-1)
this.cnt -=1
this.liftDown(0)
}
liftDown(ind){
// 和子节点比较如果小于子节点向下调整
let n = this.cnt - 1
while(leftChildIndex <= n){
let temp = ind
let leftChildIndex = ind * 2 + 1
let rightChildIndex = ind * 2 + 2
if(this.data[ind] < this.data[leftChildIndex] ) temp = leftChildIndex// leftChildIndex<=n 说明有左子节点
if(rightIndex<=n && this.data[ind]< this.data[rightChildIndex]) temp = rightChildIndex // rightChildIndex<=n说明有右子节点
if(temp == ind) break ; // 说明不需要调整
this.swap(ind ,temp) // 需要调整互换
ind = temp
}
}
}
复制代码