堆-堆排序

    堆排序,與歸併排序同樣,時間複雜度爲O(nlgn),與插入排序同樣,具備空間原址性:任什麼時候候都只須要常數個額外的元素空間存儲臨時數據。(二叉)堆是一個數組,能夠被當作一個近似的徹底二叉樹,樹上的每個結點對應數組中的一個元素。除了最底層外,該樹是徹底充滿的,並且是從左向右填充。表示堆的數組A有兩個屬性:A.length爲數組元素的個數,A.heap-size表示有多少個堆元素存儲在數組中。樹的根結點爲A[0],容易獲得父結點、左孩子和右孩子的下標:

二叉堆分爲最大堆和最小堆。結點的值都要知足堆序性質,最大堆中,堆中的最大元素存放在根結點中;而且,在任一子樹中,該子樹所包含的全部結點的值都不大於該子樹根結點的值,最小堆性質相反。
堆的基本過程:
Max-Heapify過程:時間複雜度爲O(lgn),是維護最大堆性質的關鍵。
Build-Max-Heap過程:具備線性時間複雜度,功能是從無序的輸入數據數組中構造一個最大堆。
HeapSort過程:時間複雜度爲O(nlgn),功能是對一個數據進行原址排序。
Max-Heap-Insert、Heap-Extract-Max、Heap-Increase-Key和Heap-Maximum過程:時間複雜度爲O(lgn),功能是利用堆實現一個優先隊列。

Max-Heapify的輸入爲一個數組A和一個下標i,經過讓A[i]的值在最大堆中「逐級降低",從而使得如下標i爲根結點的子樹從新遵循最大堆的性質,可經過遞歸和非遞歸兩種方式實現,代碼以下:
 1 void 
 2 percDownRecursion(int a[],int i, int n)   // max-heapify 下濾 維護最大堆性質 遞歸方式
 3 {
 4     int left = left(i);
 5     int right = right(i);
 6     int large;
 7     if(left < n && a[left] > a[i])
 8         large = left;
 9     else
10         large = i;
11     if(right < n && a[right] > a[large])
12         large = right;
13     if(large != i){
14         swap(a[i],a[large]);
15         percDownRecursion(a,large,n);
16     }
17 }
 1 void percDown(int a[],int i, int n)      //max-heapify 下濾 維護最大堆性質 非遞歸方式
 2 {
 3         int child;
 4     int tmp;
 5     
 6     for(tmp = a[i]; left(i) < n; i = child)
 7     {
 8         child = left(i);
 9         if(child != n-1 && a[child + 1] > a[child])
10             child++;
11         if(tmp < a[child])
12             a[i] = a[child];
13         else
14             break;
15     }
16     a[i] = tmp;
17 }

    建堆,能夠用自底向上的方法利用過程Max-Heapify把一個大小爲n的數組A轉換爲最大堆,A[n/2]後的元素都是樹的葉結點,每一個葉結點均可以當作只包含一個元素的堆,時間複雜度爲O(n)。。算法

1 void buildMaxHeap(int a[], int n)
2 {
3     for(int i = n/2; i >= 0; i--) // build heap 構建最大堆
4         percDownRecursion(a,i,n);
5 }

      堆排序,堆排序算法利用Build-Max-Heap將輸入數組A建成最大堆,由於數組中的最大元素總在根結點A[0]中,經過把它與A[n-1]進行互換,可讓該元素放到正確的位置,縮減堆的大小並進行下濾,從而在A[0...n-2]上構造一個新的最大堆。堆排序算法會不斷重複這一過程,直到堆的大小從n-1降到1。api

 1 void
 2 heapSort(int a[], int n)
 3 {
 4         buildMaxHeap(a,n);
 5     for(int i = n-1; i > 0; i--)
 6     {
 7         swap(a[0],a[i]);   
 8         percDownRecursion(a,0,i); //或者調用percDown(a,0,i)
 9     }
10 }

例子:數組

1 int main()
2 {
3    int a[] = {97,53,59,26,41,58,31};
4    int size = 7;
5    heapSort(a,size);
6    for(int i=0; i < size; ++i)
7      printf("%d ",a[i]);
8    printf("\n");
9  }

輸出:ui