堆是一種特別的樹狀結構,咱們首先來看看維基百科的上定義。java
堆(英語:Heap)是 計算機科學中的一種特別的樹狀 數據結構。如果知足如下特性,便可稱爲堆:「給定堆中任意節點 P 和 C,若 P 是 C 的母節點,那麼 P 的值會小於等於(或大於等於) C 的值」。若母節點的值恆 小於等於子節點的值,此堆稱爲 最小堆(min heap);反之,若母節點的值恆 大於等於子節點的值,此堆稱爲 最大堆(max heap)。在堆中最頂端的那一個節點,稱做 根節點(root node),根節點自己沒有 母節點(parent node)。
總結來講,堆是一個徹底二叉樹,最多隻有兩個子節點,而且必須保證根節點是最大的值或者最小的值,因此對於一個堆而言,根節點是最大的值或者是最小的值。node
由於堆是一棵徹底二叉樹,因此使用數組能夠高效的存儲數據。對於使用數組存儲的方式,有兩個性質很是關鍵,對於一個非根節點的節點i
來講,若是它的下標爲k
,那麼它的父節點的下標爲 (k -1)/2
,子節點的下標爲2 *k +1
和2 *k + 2
git
對於任意一個無序數組而言,實現堆化的步驟以下,咱們以構建一個最大堆爲例:算法
private Heap(int[] data) { int last_p = data.length - 1; //i是第一個非葉子節點 for (int i = (last_p - 1) / 2; i >= 0; i--) { heapify(data, i, last_p); } this.data = data; } private void heapify(int[] data, int start, int end) { int value = data[start]; int current_p = start; //左孩子 int left_p = 2 * current_p + 1; while (left_p <= end) { //右節點大於左節點 if (left_p < end && data[left_p] < data[left_p + 1]) { //移動位置到右節點 left_p++; } //當前的父節點已是最大值 if (data[left_p] < value) { break; } else { //子節點上移到父節點的位置 data[current_p] = data[left_p]; current_p = left_p; left_p = current_p * 2 + 1; } } data[current_p] = value; }
插入的算法以下:.將新增的節點放在數組的最末端,也就是數組的最後一個位置。而後計算出父節點的位置,讓當前節點與父節點比較,若是父節點比較小,交換位置。重複上述步驟,直到父節點大於當前節點或者當前節點是根節點。api
public int insert(int value) { checkSize(); int position = data.length - 1; data[position] = value; int current_p = position; int parent_p = (position - 1) / 2; while (current_p > 0) { if (data[parent_p] > value) { break; } else { data[current_p] = data[parent_p]; current_p = parent_p; parent_p = (current_p - 1) / 2; } } data[current_p] = value; return position; }
刪除的算法以下:將數組最後一個節點與當前須要刪除的節點替換,刪除最後一個節點,對於替換的節點來講,至關於進行了依次插入操做,不過此次是從上往下的插入。算法與remove相同,也是比較最大的值進行替換,直到不知足條件爲止。數組
刪除根節點 public int remove() { int root = data[0]; int last = data[data.length - 1]; data[0] = last; data = Arrays.copyOf(data, data.length - 1); if (data.length == 0) { return root; } //從頂點開始調整 int current_p = 0; int l = current_p * 2 + 1; int value = data[current_p]; while (l < data.length) { if (l < data.length - 1 && data[l] < data[l + 1]) { l++; //右孩子大 } if (data[l] <= value) { break; } else { data[current_p] = data[l]; current_p = l; l = current_p * 2 + 1; } } data[current_p] = value; return root; }
堆應用比較多的一個用處就是堆排序,對於一個數組進行堆化以後,第一個數組是最大的值,而後交換第一個數和最後一個數,這樣最大的數就落在了最後一個數組的位置。縮小數組,重複以前的步驟,最後就獲得了一個排序好的數組。數據結構
int[] data = new int[] {20, 40, 80, 33, 111, 47, 21, 90, -1}; HeapSort hs = new HeapSort(); hs.heap_array(data, data.length - 1); for (int i = 0; i < data.length - 1; i++) { int tmp = data[0]; data[0] = data[data.length - 1 - i]; data[data.length - 1 - i] = tmp; hs.heap_array(data, data.length - 2 - i); } System.out.println(Arrays.toString(data));
代碼地址: https://gitee.com/devnew/Algo...this