写点什么

前端之数据结构(七)堆

用户头像
Augus
关注
发布于: 4 小时前
前端之数据结构(七)堆

今天这一章就来介绍一下堆这种数据结构。

  • 堆是一种特殊的完全二叉树

  • 所有的节点都大于等于(最大堆)或小于等于(最小堆)它的子节点。


JS 中的堆

  • JS中通常用数组表示堆。


之前讲到的二叉树都是用 Object 表示的,这里怎么可以用数组呢?


如图:



我们可以把广度优先遍历的顺序作为数组下标,遍历的值作为数组的值,这样我们就可以表示一个堆了。



  • 左侧子节点的位置是 2 * index + 1 。

  • 右侧子节点的位置是 2 * index + 2 。

  • 父节点位置是 (index - 1)/ 2 。

堆的应用

  • 堆能高效、快速地找出最大值和最小值,时间复杂度:O(1)。

  • 找出第 K 个最大(小)元素。

如何找到第 K 个最大元素呢?

  • 构建一个最小堆,并将元素依次插入堆中。

  • 当堆的容量超过 K, 就删除堆顶。

  • 插入结束后,堆顶就是第 K 个最大元素。

首先我们先实现一个最小堆类

声明

  • 在类里,声明一个数组,用来装元素。


class MinHeap {    constructor() {        this.heap = []    }}
复制代码

实现主要方法

主要方法:插入、删除堆顶、获取堆顶、获取堆大小。

插入
  • 将值插入堆的底部,即数组的尾部。

  • 然后上移:将这个值和它的父节点进行交换,直到父节点小于等于这个插入的值。

  • 大小为 K 的堆中插入元素的时间复杂度为 O(logk)


class MinHeap {    constructor() {        this.heap = []    }
swap(i1, i2) { const temp = this.heap[i1] this.heap[i1] = this.heap[i2] this.heap[i2] = temp }
getParentIndex(i) { // 如下写,显得比较臃肿 // Math.floor((i - 1) / 2) // 可以通过二进制向前移一位的操作 // 实现除2取整的 return (i - 1) >> 1 }
shiftUp(index) { if (index === 0) return const parentIndex = this.getParentIndex(index) if (this.heap[parentIndex] > this.heap[index]) { this.swap(parentIndex, index) this.shiftUp(parentIndex) }
}
insert(value) { this.heap.push(value) this.shiftUp(this.heap.length - 1) }}
const h = new MinHeap()h.insert(3)h.insert(2)h.insert(1)
console.log(h);// MinHeap { heap: [ 1, 3, 2 ] }
复制代码


  • 虽然不能像数组那样呈递增,但是可以保证堆顶一定比后面的节点小。

删除堆顶

  • 用数组尾部元素替换堆顶(直接删除堆顶会破坏堆结构)。

  • 然后下移: 将新堆顶和它的子节点进行交换,直到子节点大于等于这个新堆顶。

  • 大小为 K 的堆中删除堆顶的时间复杂度为 O(logk)。


class MinHeap {    constructor() {        this.heap = []    }
swap(i1, i2) { const temp = this.heap[i1] this.heap[i1] = this.heap[i2] this.heap[i2] = temp }
getLeftIndex(i) { return i * 2 + 1 }
getRightIndex(i) { return i * 2 + 2 }
shiftDown(index) { const leftIndex = this.getLeftIndex(index) const rightIndex = this.getRightIndex(index) if (this.heap[leftIndex] < this.heap[index]) { this.swap(leftIndex, rightIndex) this.shiftDown(leftIndex) } if (this.heap[rightIndex] < this.heap[index]) { this.swap(rightIndex, rightIndex) this.shiftDown(rightIndex) } }
pop() { this.heap[0] = this.heap.pop() this.shiftDown(0) }}
const h = new MinHeap()h.insert(3)h.insert(2)h.insert(1)h.pop()
console.log(h)// MinHeap { heap: [ 2, 3 ] }
复制代码

获取堆顶和堆的大小

  • 获取堆顶:返回数组的头部。

  • 获取堆的大小:返回数组的长度。


class MinHeap {    constructor() {        this.heap = []    }
peek() { return this.heap[0] }
size() { return this.heap.length }}
const h = new MinHeap()h.insert(3)h.insert(2)h.insert(1)
console.log(h);// 1 3
复制代码


End~~~

用户头像

Augus

关注

爱瞎搞的软件开发工程师 2021.06.10 加入

某摸鱼集团

评论

发布
暂无评论
前端之数据结构(七)堆