如果根是兒童的存在留下的根值左孩子小於值;如果根是兒童的權利的存在的根值比他們的孩子的權利少值。
2.大根堆
如果根是兒童的存在留下的根值多名離開自己的孩子值。子女則根節點的值大於右子女的值。
3.結論
(1)堆是一棵全然二叉樹(假設公有h層,那么1~h-1層均滿,在h層連續缺失若干個右葉子)。
(2)小根堆的根節點的值是最小值,大根堆的根節點的值是最大值。
(3)堆適合於採用順序存儲。
4.堆的插入算法
將一個數據元素插入到堆中,使之依舊成為一個堆。
算法描寫敘述:先將結點插入到堆的尾部,再將該結點逐層向上調整,直到依舊構成一個堆。調整方法是看每一個子樹是否符合大(小)根堆的特點,不符合的話則調整葉子和根的位置。
5.堆的刪除算法
堆在刪除元素時,僅僅能夠刪除根節點。
算法描寫敘述:將根節點刪除后用堆尾結點進行填補,調整二叉樹,使之依舊成為一個堆。
6.堆排序(大根堆,小根堆類似)
其基本思想為(大根堆):
1)將初始待排序keyword序列(R1,R2....Rn)構建成大頂堆,此堆為初始的無序區,構建的過程是每一個非葉子結點都經過一次調整,調整順序為從底層至頂層(調整過程中含有遞歸),這樣調整下來這個二叉樹總體上就是一個大根堆(或小根堆)了;
2)將堆頂元素R[1]與最后一個元素R[n]交換。此時得到新的無序區(R1,R2,......Rn-1)和新的有序區(Rn),且滿足R[1,2...n-1]<=R[n];
3)因為交換后新的堆頂R[1]可能違反堆的性質,因此須要對當前無序區(R1,R2,......Rn-1)調整為新堆,然后再次將R[1]與無序區最后一個元素交換,得到新的無序區(R1,R2....Rn-2)和新的有序區(Rn-1,Rn)。不斷反復此過程直到有序區的元素個數為n-1,則整個排序過程完畢。
操作步驟例如以下:
1)初始化堆:將R[1..n]構造為堆;
2)將當前無序區的堆頂元素R[1]同該區間的最后一個記錄交換,然后將新的無序區調整為新的堆。
因此對於堆排序,最重要的兩個操作就是構造初始堆和調整堆,其實構造初始堆其實也是調整堆的過程,僅僅只是構造初始堆是對全部的非葉節點都進行調整。
操作過程圖示:
從上述過程可知。堆排序其實也是一種選擇排序,是一種樹形選擇排序。
僅僅只是直接選擇排序中。為了從R[1...n]中選擇最大記錄,需比較n-1次,然后從R[1...n-2]中選擇最大記錄需比較n-2次。其實這n-2次比較中有非常多已經在前面的n-1次比較中已經做過。而樹形選擇排序恰好利用樹形的特點保存了部分前面的比較結果。因此能夠降低比較次數。對於n個keyword序列。最壞情況下每一個節點需比較log2(n)次。因此其最壞情況下時間復雜度為nlog2(n)。堆排序為不穩定排序,不適合記錄較少的排序。
關於log2(n)的理解:依據堆排序的過程,每次將大根堆根節點的值跟最后一個葉子的值進行交換,那假設最后的葉子結點正好是最小的數。那么這個葉子結點就會一層層的被放到子樹終於放到葉子結點的位子(不是前面的葉子結點的位置了)。這種話這個葉子結點經過的層數就剛好為log2(n)。然而其它沒有交換的二叉樹的分支,由於曾經都是大根堆。所以大根堆的性質還是沒有變化,這一點對理解程序至關重要。C語言程序例如以下:
/*堆排序(大根堆)*/ #include <stdio.h> /*注意:這個函數僅僅會在調整被交換的位置為大根堆。未交換的分支不會處理, 所以不能將一個非大根堆二叉樹的根結點傳遞過來讓這個函數將其處理為大根堆*/ void heap_ajust(int *a, int i, int size) /*a為堆存儲數組,size為堆的大小*/ { int lchild = 2*i; //i的左孩子節點序號 int rchild = 2*i +1; //i的右孩子節點序號 int max = i; /*存放三個頂點中最大的數的下標*/ int temp; if(i <= size/2) //假設i是葉節點就不用進行調整 { if(lchild<=size && a[lchild]>a[max]) { max = lchild; } if(rchild<=size && a[rchild]>a[max]) { max = rchild; } if(max != i) { temp = a[i]; /*交換a[i]和a[max]的值*/ a[i] = a[max]; a[max] = temp; heap_ajust(a, max, size); /*被交換的位置曾經是大根堆,如今可能不是大根堆 所以須要又一次調整使其成為大根堆結構*/ } } } void build_bheap(int *a, int size) /*建立大根堆*/ { int i; for(i=size/2; i >= 1; i--) /*非葉節點最大序號值為size/2*/ { heap_ajust(a, i, size); /*每一個非葉子結點都須要調用這個函數*/ } } void heap_sort(int *a, int size) /*堆排序*/ { int i; int temp; build_bheap(a, size); for(i=size; i >= 1; i--) { temp = a[1]; a[1] = a[i]; a[i] = temp; /*交換堆頂和最后一個元素,即每次將剩余元素中的最大者放到最后面*/ heap_ajust(a, 1, i-1); /*又一次調整堆頂節點成為大頂堆,僅僅有被交換的分支才有可能不是大根堆*/ } } int main(int argc, char *argv[]) { int a[]={0,16,20,3,11,17,8}; int size = sizeof(a)/sizeof(int) -1; int i; printf("size = %d\n", size); heap_sort(a, size); printf("Sort over:"); for(i=1;i <= size; i++) printf("%d ", a[i]); printf("\n"); return 0; }程序執行截圖為:
參考博文地址:http://www.cnblogs.com/dolphin0520/archive/2011/10/06/2199741.html
版權聲明:本文博客原創文章,博客,未經同意,不得轉載。