堆的數據結構
如上圖:表示的是最小堆結構,形式上是一棵完全二叉樹,實際存儲在內存中的是一個數組,也就是對應下面的數組。樹中每一個節點左邊紅色的值,代表它們在數組中的位置。
堆中節點的關係
父節點與當前節點的下標對應關係爲:當前節點下標爲 I 則父節點的下標爲( I - 1)/2 = Parent , 左孩子節點的下標爲:2 * I+1= Lchild ,右節點的下標爲:2 * I+2= Rchild 。
插入堆
①插人2節點,與其父節點5比較,2比5小交換位置。
②插人3節點,與其父節點2比較,3比2大位置不變。
③插人4節點,與其父節點5比較,4比5小交換4和5的位置,4繼續與其父節點2比較,4比2大不變。
上面插入的過程總結一下:每一個插入的節點放在樹的最後一個位置,與其父節點比較,如果比父節點小交換位置,繼續與其父節點比較直到比父節點大,或者到了頭節點位置停止比較。
代碼:
public void inSertMinHeap(int arr[],int i) { int parent=(i-1)/2; while(parent>=0&&arr[i]<arr[parent]) { //如果父節點的下標大於0、並且當前節點小於父節點交換位置。繼續向上比較,否則停止比較。 if(i==0) break; int temp=arr[parent]; arr[parent]=arr[i]; arr[i]=temp; i=parent; parent=(i-1)/2; } }
看下Java api中關於插入堆的操作:
private void siftUp(int k, int arr[]) { int key=arr[k]; while (k > 0) { int parent = (k - 1) >>> 1; int e = arr[parent]; if(arr[parent]<arr[k]) break; k = parent; } arr[k] = key; }
因爲插入堆是從底往上的操作因此在api中名稱爲 siftUp。
調整堆
刪除元素後要對堆進行調整:
堆中每次刪除只能刪除頭節點。也就是數組中的第一個節點。
將最後一個節點替代頭節點然後進行調整。
如果左右節點中的最小節點比當前節點小就與左右節點的最小節點交換。直到當前節點無子節點,或者當前節點比左右節點小時停止交換。
代碼:
public void heapify(int arr[],int i) { int l=2*i+1; int r=2*i+2; int lestgest=i; //用於保存最小節點的下標 while(l<arr.length) { if(arr[l]<arr[lestgest]) { lestgest=l; } if(r<arr.length&&arr[r]<arr[lestgest]) { lestgest=r; } int temp=arr[i]; arr[i]=arr[lestgest]; arr[lestgest]=temp; if(i==lestgest) break; i=lestgest; l=2*i+1; r=2*i+2; } }
堆化的遞歸代碼:
//遞歸的調用heapify方法。
public static void Heapify(int array[],int n,int i) { int Lestgest=i; int L=2*i; //L是i的左孩子節點 int R=2*i+1; //R是i的右孩子節點 if(L<n&&array[Lestgest]>array[L]) { Largest=L; } if(R<n&&array[Lestgest]>array[R]) { Largest=R; } //找出左右孩子節點中的最大者 if(Largest!=i) { //如果左右孩子節點的最大值比父節點值大的時候,交換 //遞歸的調整左右節點中最大的節點的分支。 int temp=array[Lestgest]; array[Lestgest]=array[i]; array[i]=temp; Heapify(array, n, Lestgest); } }
堆排序思想:
堆排序分爲三個過程:
①建堆:對數組建堆可以採用從插入堆的方法,從頭結點開始不斷的進行插入堆。也可以使用堆化的方法從最後節點的父節點開始進行從下往上進行堆化。
②堆排序:每次選擇堆頂元素,並將堆頂元素刪除,調整堆後,再重複操作直至堆爲空。
代碼:
package Sort; import java.util.Arrays; public class MyHeapSort { public static void main(String[] args) { int array[]={1,5,7,3,2,9,4}; myHeapSort(array); System.out.println(Arrays.toString(array)); } public static void myHeapSort(int array[]) { BuildHeap(array); //先建立小根堆,使得第一個元素是最小值 for(int i=array.length-1;i>=0;i--) { int temp=array[0]; array[0]=array[i]; array[i]=temp; //數組的第一個元素與後面的元素交換,因爲第一個元素總是當前堆的最小元素 //注意在排序的時候堆是在減小的 Heapify(array,i,0); //交換掉第一個元素後,要對堆進行調整,保證第一個元素仍是最小值 } } //使用調整堆從底往上進行建堆 public static void BuildHeap(int array[]) { for(int i=array.length/2;i>=0;i--) { Heapify(array,array.length,i); //建立堆的過程就是完全二叉樹,從下到上調整堆的過程,i=array.length/2開始 //依次向上調整,i=array.length/2是最後一個節點的父節點i=0是第一個節點 } } //使用插入堆的方法從上往下進行建堆 public static void BuildHeap(int array[]){ for(int i=0;i<array.length;i++) { inSertMinHeap(array,i); } } }
————————————————
版權聲明:本文爲CSDN博主「HankingHu」的原創文章,遵循CC 4.0 BY-SA版權協議,轉載請附上原文出處鏈接及本聲明。
原文鏈接:https://blog.csdn.net/u013309870/article/details/68578011