堆其實是個很簡單的資料結構
說到堆這種資料結構,很多人的第一反應是感覺很複雜,其實不然,堆就是個優先順序佇列而已,或者,堆其實就是一種樹。本文先講原理,後面給出堆的實現程式碼。
優先順序佇列可以用有序陣列來實現,這種做法的問題是,儘管刪除最大資料項的時間複雜度為O(1),但是插入還是需要較長的O(N)時間,這是因為必須移動陣列中平均一半的資料項以插入新資料項,並在完成插入後,陣列依然有序。
本文主要介紹實現優先順序佇列的另一種結構:堆。堆是一種樹,並非java和C++等編譯語言裡的“堆”。由它實現的優先順序佇列的插入和刪除的時間複雜度都是O(logN)。儘管這樣刪除的時間變慢了一些,但是插入的時間快的多了。當速度非常重要,且有很多插入操作是,可以選擇堆來實現優先順序佇列。堆有如下特點:
-
它是完全二叉樹。即除了樹的最後一層節點不需要是滿的外,其他的每一層從左到右都完全是滿的。
-
它常常用一個數組實現。用陣列實現的完全二叉樹中,節點的索引有如下特點(設該節點的索引為x):
它的父節點的索引為 (x-1) / 2; 它的左子節點索引為 2x + 1; 它的右子節點索引為 2x + 2。 -
堆中每個節點的關鍵字都大於(或等於)這個節點的子節點的關鍵字。這也是堆中每個節點必須滿足的條件。所以堆和二叉搜尋樹相比,是弱序的。
向堆中插入資料,首先將資料項存放到葉節點中(即存到陣列的最後一項),然後從該節點開始,逐級向上調整,直到滿足堆中節點關鍵字的條件為止。
從堆中刪除資料與插入不同,刪除時永遠刪除根節點的資料,因為根節點的資料最大,刪除完後,將最後一個葉節點移到根的位置,然後從根開始,逐級向下調整,直到滿足堆中節點關鍵字的條件為止。
原理就這麼多,堆真的很簡單。
下面給出堆的實現程式碼:
package com.jt.ec.salesorder.web.controller; public class Heap { private Node[] heapArray; private int maxSize; private int currentSize; public Heap(int mx) { maxSize = mx; currentSize = 0; heapArray = new Node[maxSize]; } public boolean isEmpty() { return (currentSize == 0) ? true : false; } public boolean isFull() { return (currentSize == maxSize) ? true : false; } public boolean insert(int key) { if (isFull()) { return false; } Node newNode = new Node(key); heapArray[currentSize] = newNode; trickleUp(currentSize++); return true; } // 向上調整 public void trickleUp(int index) { int parent = (index - 1) / 2; // 父節點的索引 Node bottom = heapArray[index]; // 將新加的尾節點存在bottom中 while (index > 0 && heapArray[parent].getKey() < bottom.getKey()) { heapArray[index] = heapArray[parent]; index = parent; parent = (parent - 1) / 2; } heapArray[index] = bottom; } public Node remove() { Node root = heapArray[0]; heapArray[0] = heapArray[--currentSize]; trickleDown(0); return root; } // 向下調整 public void trickleDown(int index) { Node top = heapArray[index]; int largeChildIndex; while (index < currentSize / 2) { // while node has at least one child int leftChildIndex = 2 * index + 1; int rightChildIndex = leftChildIndex + 1; // find larger child if (rightChildIndex < currentSize // rightChild exists? && heapArray[leftChildIndex].getKey() < heapArray[rightChildIndex].getKey()) { largeChildIndex = rightChildIndex; } else { largeChildIndex = leftChildIndex; } if (top.getKey() >= heapArray[largeChildIndex].getKey()) { break; } heapArray[index] = heapArray[largeChildIndex]; index = largeChildIndex; } heapArray[index] = top; } // 根據索引改變堆中某個資料 public boolean change(int index, int newValue) { if (index < 0 || index >= currentSize) { return false; } int oldValue = heapArray[index].getKey(); heapArray[index].setKey(newValue); if (oldValue < newValue) { trickleUp(index); } else { trickleDown(index); } return true; } public void displayHeap() { System.out.println("heapArray(array format): "); for (int i = 0; i < currentSize; i++) { if (heapArray[i] != null) { System.out.print(heapArray[i].getKey() + " "); } else { System.out.print("--"); } } } } class Node { private int iData; public Node(int key) { iData = key; } public int getKey() { return iData; } public void setKey(int key) { iData = key; } }
引自:https://mp.weixin.qq.com/s/puq01hD6H9rHBr3mBXZpxw