前端之数据结构(七)堆

这是我参与8月更文挑战的第八天,活动详情查看:8月更文挑战前端

前端之数据结构(六)图数组

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

  • 堆是一种特殊的彻底二叉树数据结构

  • 全部的节点都大于等于(最大堆)或小于等于(最小堆)它的子节点。app

image.png

JS中的堆

  • JS中一般用数组表示堆。

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

如图:ui

image.png 咱们能够把广度优先遍历的顺序做为数组下标,遍历的值做为数组的值,这样咱们就能够表示一个堆了。this

image.png

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

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

  • 父节点位置是 (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~~~

相关文章
相关标签/搜索