堆的產生
堆的產生問題背景:如何在一堆動態變化的數中,以O(1)的複雜度獲取最值。
堆的目標:一個數組,支持刪除元素和添加元素,保證首元素永遠是數堆中的最值。
數組樹形化:比如給出數組 , 一層一層依次從左到右加入節點,構造出如下圖所示的一顆樹,該種樹形稱爲完全二叉樹。
對於數組 ,其所有元素的父子關係滿足。
完全二叉樹:每一層節點都是滿的,最底下一層葉子節點從左到右也是滿的。
完全二叉樹的數組化:可以用數組存儲,按層次從左到右遍歷樹節點。比如下圖。
堆的定義:
- 邏輯上是一個完全二叉樹,支持刪除元素和添加元素,保證根元素永遠是數堆中的最值。其所有子樹也都是堆。
- 物理存儲上,因爲完全二叉樹的節點可由數組存儲,所以是一個數組,所有節點的父/子節點在數組中的位置,可由公式計算得到。以 爲例,數組位置從 0 開始計。 的位置是 ,其父節點位置是 ,左子節點下標是 ,右子節點下標是 。
堆示例: 就不是堆,因爲 不是最值,且以 爲根的子樹,根也不是最值。 是堆,樹形化後如下圖所示:
建堆
建堆的目標:以前面的數組 爲例,調整元素位置,使之對應的完全二叉樹,符合堆定義。
建堆的思路:把問題分解,從最小的樹開始調整。
- 先找到完全二叉樹中最低層的父節點。按父子關係公式逆運算,元素下標是 ,就是 。該樹只有最多三個節點,父節點與子節點中最大的節點互換位置,如果父節點最大就按兵不動。此時該元素( )爲根的子樹滿足堆定義。
- 繼續往前調整節點,此時元素下標是 ,就是 ,父子節點進行同樣的比較互換操作 ,如果有更換(與 互換了),那麼無法保證新的子節點值 是子樹的最大值,所以需要繼續將該子節點 和其子節點 進行同樣的比較互換操作,一直進行到比較時無需更換,或者沒有子節點爲止。
- 繼續往前發現已經到數組首元素前面了,結束。
- 前面對節點 一路向下的比較調整,稱爲向下調整。而前面從最低父節點 開始的建堆,我自稱爲向前建堆。
插入與刪除元素
插入和刪除的背景: