最大堆 最大堆資料結構是一棵完全二叉樹( 分葉節點只能出現在最下層和次下層,並且最下面一層的結點都集中在該層最左邊的若干位置的二叉樹)。
因為完全二叉樹的性質,因此我們用數組來儲存樹的節點,從上到下,從左至右,按序存在數組,而且子節點的值得小於等於父節點的值。因此堆的根節點是數組中的最大值,這即是最大堆。最大堆經常用於實現優先隊列。舉個栗子:比如英雄聯盟或王者榮耀中的英雄在他的攻擊範圍內,他會優先攻擊更重要的敵方單位,那些在他攻擊範圍內的敵方單位就在一個最大堆中,取出最大堆的根節點即最應該被優先攻擊的那個,攻擊它。當又有敵方單位進入攻擊範圍,則插入最大堆中,並維護最大堆的性質。 下面最大堆的實現以及堆排序的實現:
//實現最大堆(用數組來存放完全二叉樹中的節點,從上到下,從左至右排序,按序存在數組,子節點的值小於等於父節點的值)public class Heap {private int[] data;private int count; //當前節點數private int capacity; //容量public Heap(int capacity) {this.data=new int[capacity+1]; //因為索引0不存節點,所以長度加一this.capacity=capacity;this.count=0;}//將一個無序數組構造成一個最大堆 相當於堆排序public Heap(int[] arr,int n){data=new int[n+1];capacity=n;for(int i=0;i<n;i++){data[i+1]=arr[i];}count=n;for(int i=count/2;i>=1;i--){ //i=count/2:i是最後一個葉子節點的父節點(最後一個非葉子節點)shiftDown(i);}}private void shiftUp(int i){while((i>1)&&(data[i/2]<data[i])){ //data[i/2]為當前節點的父節點swap(data,i,i/2);i=i/2; //更新索引}}private void shiftDown(int k){while((2*k)<=count){ //有左子節點 int j=2*k; //這輪迴圈,data[k]和data[j]交換位置 if((j+1)<=count&&(data[j+1]>data[j])){ //有右子節點且右邊的更大 j+=1; } if(data[k]>=data[j]) //如果父節點大於等於子節點,則停止迴圈 break; swap(data,k,j); k=j; //k被賦為當前位置,為下次迴圈做初始化}}public int size() {return count;}public boolean isEmpty(){return count==0;}public void insert(int a){assert((count+1)<=capacity); //防止數組越界data[count+1]=a; //從索引1開始存count++; shiftUp(count); //由於可能新添加的數違背最大堆的定義,所以要重排序}public int extractMax(){ //彈出最大值,即根節點assert(count>0);int ret=data[1];swap(data,1,count); //將最後數放到第一位置,保持完全二叉樹的結構count--;shiftDown(1); //將第一個數移至合適位置,保持最大堆性質return ret;}public static void swap(int[] arr,int a,int b){int c=arr[a];arr[a]=arr[b];arr[b]=c;}public static void situheapsort(int[] arr,int n){ //原地堆排序(就是堆排序),從0開始存for(int i=(n-1)/2;i>=0;i--){ //i=(n-1)/2:i是最後一個葉子節點的父節點(最後一個非葉子節點)__shiftDown(arr,n,i); //將一個完全無序的數組arr構造成最大堆}for(int i=n-1;i>0;i--){swap(arr,0,i); //第一個即最大值與最後一個值交換__shiftDown(arr,i,0); //把第一個較小的值放在合適位置,此時的數組長度為n-1}}public static void __shiftDown(int[] arr,int n,int k){while((2*k+1)<n){ //有左子節點 int j=2*k+1; //這輪迴圈,arr[k]和arr[j]交換位置 if((j+1)<n&&(arr[j+1]>arr[j])){ //有右子節點且右邊的更大 j+=1; } if(arr[k]>=arr[j]) //如果父節點大於等於子節點,則停止迴圈 break; swap(arr,k,j); k=j; //k被賦為當前位置,為下次迴圈做初始化}}public static void main(String[] args) {Heap heap=new Heap(100);System.out.print("插入的數為:");for(int i=0;i<30;i++){int rand=new Random().nextInt(100)+1;System.out.print(rand+" ");heap.insert(rand);}System.out.println();System.out.print("heap.extractMax():");while(!heap.isEmpty()){System.out.print(heap.extractMax()+" "); //從大到小輸出}System.out.println();System.out.println("*********************堆排序*********************************");int arr[] =MAIN.geneateArrays(30);situheapsort(arr,arr.length);for(int i=0;i<arr.length;i++){System.out.print(arr[i]+" ");}}}列印結果: