咱們常常提到的數據結構大頂堆指的是二叉堆,它是一顆堆有序的徹底二叉樹(非葉子結點層都是滿的,最後一層從右向左只能空缺右結點)。其中根節點是全部結點中最大,而且每一個父節點都大於其兩個子節點(堆有序)。徹底二叉樹底層是用數組實現的,因此它只是邏輯上的一個概念。下圖是一個大頂堆的例子:算法
那麼給定一個數組怎麼創建大頂堆呢?咱們用下面代碼來講明,創建堆的時間複雜度爲O(n)。api
1 //創建大頂堆 2 public void creatHeap(int[] arr) { 3 for (int i=0; i<arr.length; i++) { 4 heapInsert(arr, i); 5 } 6 } 7 /** 8 * 某一個元素進堆,元素上浮的過程 9 * @param arr 10 * @param index 11 */ 12 public void heapInsert(int[] arr, int index) { 13 //當前元素大於父節點時,交換 14 while (arr[index] > arr[(index - 1) / 2]) { 15 swap(arr, index, (index - 1) / 2); 16 // 來到父節點位置繼續比較 17 index = (index - 1) / 2; 18 } 19 } 20 21 public void swap(int[] arr, int m, int n) { 22 int temp = arr[m]; 23 arr[m] = arr[n]; 24 arr[n] = temp; 25 }
若是說堆中某個元素變小了,咱們可使用heapify來調整元素的位置,使得堆仍然是大頂堆,heapify其實是當前元素下沉的過程,具體代碼以下:數組
1 /** 2 * 元素下沉過程 3 * @param arr 4 * @param index 當前變小的元素 5 * @param heapSize 堆的大小,小於等於數組的大小 6 */ 7 public void heapify(int[] arr, int index, int heapSize) { 8 //左右孩子結點的索引,數組的索引從0開始 9 int left = 2 * index + 1; 10 int right = left + 1; 11 12 while (left < heapSize) { 13 //從左右孩子中選出大的 14 int largest = right < heapSize && arr[right] > arr[left] ? right : left; 15 //和index比較 16 largest = arr[largest] > arr[index] ? largest : index; 17 //當前變小的元素任然比左右孩子結點大,結束循環 18 if (largest == index) break; 19 //交換 20 swap(arr, largest, index); 21 //更新index位置,來到largest的位置 22 index = largest; 23 //重置left位置,繼續向下比較 24 left = 2 * index + 1; 25 } 26 }
優先隊列本質仍是一個隊列,只不過隊列裏的元素有優先級,優先級高的元素先出隊列。在Java中優先隊列有兩種實現,一種是大頂堆,另一種是小頂堆。以大頂堆爲例:當隊首元素彈出時,優先隊列會自動調整剩下的元素,使其還是一個大頂堆,時間複雜度爲O(nlogn)。具體實現過程就利用了咱們上面的heapify方法,一樣給出代碼說明:數據結構
1 public void heapSort(int[] arr) { 2 int len = arr.length; 3 //交換首尾元素,使得彈出的元素在堆中失效,但仍在數組中 4 swap(arr, 0, --len); 5 //不斷地進行heapify操做 6 while (len > 0) { 7 heapify(arr, 0, len); 8 swap(arr, 0, --len); 9 } 10 }
優先隊列能夠應用於系統的任務調度,優先級高的任務先執行,低的在隊列中等候;圖的搜索算法中也會用到優先隊列,感興趣的童鞋能夠閱讀《算法》第四版具體學習。學習
參考資料:左程雲算法初級班spa
《算法》第四版3d