前端之數據結構(七)堆

這是我參與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~~~

相關文章
相關標籤/搜索