? (二叉)堆(heap)數據結構是一種數組對象,可以視作一顆完全二叉樹,從該二叉樹的根開始層次遍歷這顆二叉樹就可以得到其對應的數組。樹的根節點為A[0],對于樹中某個節點的坐標i,其左右孩子節點和父親節點的坐標可以很方便的求得:
?? LEFT(i)=2*i+1; RIGHT(i)=2*i+2; PARENT(i)=i/2 .
? 有兩種二叉堆:最大堆和最小堆。最大堆中,每個節點存儲的數值都大于等于其左右兩個孩子節點存儲的數值,亦即A[i]>=A[LEFT[i]]&&A[i]>=A[RIGHT[i]]。最小堆則正好相反。本文以最大堆為例。
? 知道了最大堆的定義之后,就要在給定的任意數組上構建最大堆,然后利用這個最大堆進行升序排序:
? (1) 構建最大堆:
? 首先我們定義一個方法Heapify(heap,i),如果以i的左右孩子節點為根的子樹已經是最大堆,則該方法使得以i為根的子樹也成為最大堆。其偽代碼如下(摘自《算法導論》):
1 MAX- HEAPIFY(A,i) 2 l= LEFT(i) 3 r= RIGHT(i) 4 target= i; 5 if (l<=A.heap_size&&A[l]> A[i]) 6 target= l; 7 if ( if (r<=A.heap_size&&A[r]> A[i])) 8 target= r; 9 if (target!= i) 10 exchange(A[i],A[target]) 11 MAX-HEAPIFY(A,target)//遞歸
? 我們比較當前節點i的數值和其左右子節點的數值,如果i的某個子節點的數值大于i的數值,則違反了最大堆的定義,所以我們需要交換這兩個節點的位置。假設A[LEFT[i]]>A[RIGHT[i]]>A[i],則交換i節點與LEFT[i]節點。但是,被交換到左孩子節點的i節點可能會違反以左孩子結點為根的最大堆的定義,所以我們需要對這個最大堆遞歸調用MAX-HEAPIFY方法。
? 有了上面這個方法之后,我們就可以自底向上的調用MAX-HEAPIFY方法構建最大堆。因為A[A.length/2+1]及其之后的節點都是葉子節點,都可以看做只有一個節點的最大堆,所以我們可以從A[A.length/2]節點開始直到A[0]節點依次調用MAX-HEAPIFY方法,亦即從樹的層次遍歷的最后一個有孩子的節點開始,按照層次遍歷的逆序調用MAX-HEAPIFY方法:
1 BUILD-MAX- HEAP(A) 2 for i=A.length/ 2 downto 1 3 MAX-HEAPIFY(A,i)
? (2) 堆排序
? 構造完最大堆之后,我們就可以利用其進行排序。因為最大堆只能保證A[0]存儲的是當前堆中最大的元素,我們可以把A[0]與堆的最后一個元素互換,這樣A[0]就排在了最后一個位置,也是正確的位置。這時最后一個位置已經不屬于最大堆,所以A.heap_size要減一。互換到A[0]的元素可能會破壞最大堆的性質,我們可以調用MAX-HEAPIFY方法使之重新成為最大堆,然后將A[0]交換至當前堆的最后一個位置。依次遞歸。
1 HEAPSORT(A) 2 for i=A.length downto 2 3 exchange(A[i],A[ 0 ]) 4 --A.heap_size // 堆的大小減少 5 MAX-HEAPIFY(A, 0 )
? (3) 堆的JAVA實現
?
1 package Algorithm; 2 3 import java.util.* ; 4 /** 5 * 堆(Heap) 6 * @author Kemaswill 7 * 2012-10-5 Friday 8 */ 9 10 public class Heap { 11 12 public static int [] data; 13 public static int length; 14 public static int heap_size; 15 16 public Heap(){ 17 this .length=20 ; 18 this .heap_size= length; 19 this .data= new int [length]; 20 Random random= new Random(System.currentTimeMillis()); 21 for ( int i=0;i<length;i++ ){ 22 data[i]=Math.abs(random.nextInt()%50 ); 23 } // for 24 } 25 26 public Heap( int n){ 27 this .length= n; 28 this .heap_size= length; 29 this .data= new int [length]; 30 Random random= new Random(System.currentTimeMillis()); 31 for ( int i=0;i<length;i++ ){ 32 data[i]=Math.abs(random.nextInt()%50 ); 33 } // for 34 } 35 36 public static void max_heapify(Heap heap, int i){ 37 if (i< heap.heap_size){ 38 int l=2*i+1 ; 39 int r=2*i+2 ; 40 int target= i; 41 if (l<heap.heap_size&&heap.data[l]> heap.data[i]){ 42 target= l; 43 } 44 if (r<heap.heap_size&&heap.data[r]> heap.data[target]){ 45 target= r; 46 } 47 if (target!= i){ 48 exchange(heap,i,target); 49 max_heapify(heap,target); 50 } // if 51 } // if 52 } // heapify 53 54 public static void exchange(Heap heap, int x, int y){ 55 int tmp= heap.data[x]; 56 heap.data[x]= heap.data[y]; 57 heap.data[y]= tmp; 58 } 59 60 public static void build_heap(Heap heap){ 61 // 對于所有非葉結點,依次調用max_heapify 62 for ( int i=heap.heap_size/2;i>=0;i-- ){ 63 max_heapify(heap,i); 64 } 65 } 66 67 public static void heapsort(Heap heap){ 68 69 for ( int i=heap.length-1;i>0;i-- ){ 70 exchange(heap,0 ,i); 71 heap.heap_size-- ; 72 max_heapify(heap,0 ); 73 } 74 } // heapsotr 75 76 public static void show_heap(Heap heap){ 77 for ( int i=0;i<=( int )Math.log(heap.length)/Math.log(2)+2;i++ ){ 78 for ( int j=( int )Math.pow(2, i)-1;j<Math.pow(2, i+1)-1;j++ ){ 79 if (j< heap.length){ 80 System.out.print(heap.data[j]+" " ); 81 } 82 else break ; 83 } 84 System.out.println(); 85 } 86 } 87 88 public static void main(String[] args){ 89 Heap heap= new Heap(); 90 show_heap(heap); 91 build_heap(heap); 92 show_heap(heap); 93 heapsort(heap); 94 show_heap(heap); 95 96 } // main 97 98 }
?
? 參考文獻:
? [1] 《算法導論》 第6章 p73
? [2] 一個用Java實現的簡單的最大堆
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
