「掃盲」數據結構 - 堆入門

什麼是堆

  • 堆是一顆【徹底二叉樹
  • 堆的全部【根節點】「大於」【子節點

    這裏的大因而能夠定義的。git

<img src="https://gitee.com/xiaoxiunique/picgo-image/raw/master/atips/image-20200318211957067.png" alt="image-20200318211957067" style="zoom:50%;" />api

​ 上圖所示,都是知足堆上方的性質,一顆徹底二叉樹,全部的根節點大於子節點數組

​ 上方展現的爲最大堆(相應的也能夠定義最小堆)工具

  • 使用數組表示

    <img src="https://gitee.com/xiaoxiunique/picgo-image/raw/master/atips/image-20200318212734956.png" alt="image-20200318212734956" style="zoom:50%;" />spa

    由於堆知足徹底二叉樹的定義,因此堆可使用數組來表示【上圖所示】。code

    由上圖得在 index 位置上的節點能夠推倒出以下公式 parent(i) = i / 2 left child (i) = 2 * i right child (i) = 2 * i + 1ip

    可是在上圖中,實際上是浪費了數組的零號位置,若是元素從0號位置排將會是下面的結構get

    <img src="https://gitee.com/xiaoxiunique/picgo-image/raw/master/atips/image-20200318213435336.png" alt="image-20200318213435336" style="zoom:50%;" />博客

    由上圖能夠推倒公式爲:it

    parent(i) = (i - 1) / 2 left child (i) = 2 * i + 1 right child (i) = 2 * i + 2

堆中的經常使用操做

  • Sift Up (向堆中添加元素)

    上浮,由於堆底層實現爲數組,因此咱們在添加元素的時候是直接向數組的末端添加元素,這樣就始終保證堆是一個徹底二叉樹,可是咱們須要維持二叉樹第二個性質,根節點元素大於子節點,因此咱們須要 sift up 操做

    假設有以下堆結構:

    <img src="https://gitee.com/xiaoxiunique/picgo-image/raw/master/atips/image-20200318214332416.png" alt="image-20200318214332416" style="zoom:50%;" />

    假設咱們如今須要添加的元素爲 52,如今元素的位置爲 arr[arr.length - 1],可是這樣就違反了堆的結構,由於 52 > 16sift up 就是若是當前元素大於根節點元素的值那麼就交換兩個元素,【迭代】執行,直到知足子節點小於根節點。

    這時咱們就須要交換 52 和 16號元素的值

    <img src="https://gitee.com/xiaoxiunique/picgo-image/raw/master/atips/image-20200318214919048.png" alt="image-20200318214919048" style="zoom:50%;" />

    交換完成後是這個樣子

    <img src="https://gitee.com/xiaoxiunique/picgo-image/raw/master/atips/image-20200318215227768.png" alt="image-20200318215227768" style="zoom:50%;" />

    可是這時候又會發現仍是不知足堆結構,由於 52 > 41,因此 52 和 41 還須要交換

    <img src="https://gitee.com/xiaoxiunique/picgo-image/raw/master/atips/image-20200318215332914.png" alt="image-20200318215332914" style="zoom:50%;" />

    交換後才又知足堆的結構

    <img src="https://gitee.com/xiaoxiunique/picgo-image/raw/master/atips/image-20200318215450242.png" alt="image-20200318215450242" style="zoom:50%;" />

    上面 52 號元素移動的整個過程,稱之爲 sift up 上浮

    <img src="https://gitee.com/xiaoxiunique/picgo-image/raw/master/atips/heap_sift_up.png" style="zoom:80%;" />

  • Sift Down (取出堆中的最大元素)

    由堆的特性所得,根節點的元素爲堆中的最大元素,因此咱們只須要取出根節點便可。

    <img src="https://gitee.com/xiaoxiunique/picgo-image/raw/master/atips/image-20200318220445853.png" alt="image-20200318220445853" style="zoom:50%;" />

    可是若是直接取出根節點就會致使將原來的堆切割爲兩個堆,後續在合併的時候就會變的異常麻煩,因此咱們這裏轉變一下思路,直接將末尾的元素 arr[arr.length - 1] 16 與 根節點62 交換位置,然後再將其處理爲堆結構這樣會簡單不少

    <img src="https://gitee.com/xiaoxiunique/picgo-image/raw/master/atips/image-20200318220722116.png" alt="image-20200318220722116" style="zoom:50%;" />

    如上圖所示,直接將末尾的元素替換掉頭結點。此時就違反了堆結構,咱們就須要進行 Sift Down 的操做。

    當前元素與它的左右孩子進行對比,與左右孩子中較大的孩子進行交換,迭代進行,最終即可完成 Sift Down

    <img src="https://gitee.com/xiaoxiunique/picgo-image/raw/master/atips/image-20200318221110695.png" alt="image-20200318221110695" style="zoom:50%;" />

    第一次交換 16 和 50 ,由於 52 > 30,交換後的效果爲

    <img src="https://gitee.com/xiaoxiunique/picgo-image/raw/master/atips/image-20200318221300114.png" alt="image-20200318221300114" style="zoom:50%;" />

    第二次 交換 16 和 42,由於 42 > 16

    <img src="https://gitee.com/xiaoxiunique/picgo-image/raw/master/atips/image-20200318221601439.png" alt="image-20200318221601439" style="zoom:50%;" />

    通過前面的兩次交換後,如今就知足最大堆的性質了。

    上面兩次交換的過程就稱爲 Sift Down

    <img src="https://gitee.com/xiaoxiunique/picgo-image/raw/master/atips/heap_sift_down.png" style="zoom:80%;" />

  • replace
  • heapity
本文由博客羣發一文多發等運營工具平臺 OpenWrite 發佈
相關文章
相關標籤/搜索