花了些時間好好看了堆排序的內容,代碼也敲了,如今來總結一下。web
爲了說明白點,有些圖片我就從網上截取了。windows
首先是堆的概念。數組
數據結構中的堆,又叫二叉堆數據結構
通常用數組來表示堆得結構,或者說是把堆數組化。舉個列子來看:函數
這樣就很清楚的看出了堆的儲存結構。spa
接着就是堆得操做處理了。.net
首先堆的插入操做:code
上代碼:orm
1 void Heap_insert_fix(int a[],int n) 2 { 3 int temp; 4 int i,j; 5 i = n; 6 j = (i - 1) / 2;/*父節點*/ 7 temp = a[i];/*記錄插入的數據*/ 8 while(i != 0 && j >= 0) 9 { 10 if(a[j] <= temp) 11 break; 12 a[i] = a[j]; 13 i = j; 14 j = (i - 1) / 2; 15 } 16 a[i] = temp; 17 }
上面代碼解析:blog
先明白這點,
*父節點 i 子節點則爲 j = i*2 +1
*子節點 i 父節點則爲 j = (i-1) / 2
而後,插入的流程是,每次插入的數據都是在葉子節點,接着調整。直到知足堆得性質爲止!
而後是堆的刪除操做:
原理:每次刪除根節點,就是用葉子節點覆蓋根節點
上代碼:
1 /* 2 *刪除操做 3 *刪除根結點,而後調整 4 *從i節點開始,總數有n個 5 */ 6 void Heap_del_fix(int a[],int i,int n) 7 { 8 int j; 9 int temp; 10 temp = a[i]; 11 j = i * 2 + 1;/*子節點*/ 12 while(j < n) 13 { 14 if(a[j] > a[j+1] && j+1 < n) 15 j++; 16 if(a[j] >= temp) 17 break; 18 a[i] = a[j]; 19 i = j; 20 j = i*2 + 1; 21 } 22 a[i] = temp; 23 }
它的調用函數:
1 /* 2 *調用 3 */ 4 void Heap_sub(int a[],int n) 5 { 6 swap(&a[0],&a[n-1]); 7 Heap_del_fix(a,0,n-1); 8 }
有了上面這兩個操做的基礎,下面我就來寫排序操做!
思想:
咱們有了刪除操做,每次刪除根節點,並且咱們知道根節點是數組中數值最小的那個值(我這裏是小堆模式,大堆相反),這樣咱們一次次的刪除,就造成了一個有序的序列。獲取這個序列就是咱們想要的堆排序結果。
怎麼獲取,使用數組,看代碼:
1 /* 2 *堆排序 3 */ 4 void Heap_sort(int a[],int n) 5 { 6 int i; 7 for(i=n-1;i>=1;i--) 8 { 9 swap(&a[0],&a[i]); 10 Heap_del_fix(a,0,i); 11 } 12 }
這樣倒序即是咱們的序列。
至於如何將堆數組化,代碼以下:
1 /* 2 *堆化數組 3 */ 4 void create_heap(int a[], int n) 5 { 6 int i; 7 for(i=n/2-1;i>=0;i--)/*將數組轉成堆,分開調整*/ 8 { 9 Heap_del_fix(a,i,n); 10 } 11 }
這裏的i=n/2-1;咱們最好畫圖來看,這樣理解會容易些。這部分我是在紙上實現的,讀者能夠本身嘗試。
對於swap函數,一個比較好的寫法以下:
1 void swap(int *i,int *j) 2 { 3 *i = *i ^ *j; 4 *j = *i ^ *j; 5 *i = *i ^ *j; 6 }
異或來交換兩個數的寫法,不需額外的變量。
總體代碼以下:
1 /* 2 *堆排序 3 *丁洋 4 *說明:堆用數組來表示,那麼 5 *父節點 i 子節點則爲 j = i*2 +1 6 *子節點 i 父節點則爲 j = (i-1) / 2 7 * 8 */ 9 #include<stdio.h> 10 #include<stdlib.h> 11 12 void swap(int *i,int *j) 13 { 14 *i = *i ^ *j; 15 *j = *i ^ *j; 16 *i = *i ^ *j; 17 } 18 /* 19 *插入操做 20 *堆尾插入,而後調整 21 */ 22 void Heap_insert_fix(int a[],int n) 23 { 24 int temp; 25 int i,j; 26 i = n; 27 j = (i - 1) / 2;/*父節點*/ 28 temp = a[i];/*記錄插入的數據*/ 29 while(i != 0 && j >= 0) 30 { 31 if(a[j] <= temp) 32 break; 33 a[i] = a[j]; 34 i = j; 35 j = (i - 1) / 2; 36 } 37 a[i] = temp; 38 } 39 /* 40 *調用 41 */ 42 void Heap_add(int a[],int n,int Num) 43 { 44 a[n] = Num; 45 Heap_insert_fix(a,n); 46 } 47 48 /* 49 *刪除操做 50 *刪除根結點,而後調整 51 *從i節點開始,總數有n個 52 */ 53 void Heap_del_fix(int a[],int i,int n) 54 { 55 int j; 56 int temp; 57 temp = a[i]; 58 j = i * 2 + 1;/*子節點*/ 59 while(j < n) 60 { 61 if(a[j] > a[j+1] && j+1 < n) 62 j++; 63 if(a[j] >= temp) 64 break; 65 a[i] = a[j]; 66 i = j; 67 j = i*2 + 1; 68 } 69 a[i] = temp; 70 } 71 /* 72 *調用 73 */ 74 void Heap_sub(int a[],int n) 75 { 76 swap(&a[0],&a[n-1]); 77 Heap_del_fix(a,0,n-1); 78 } 79 80 /* 81 *堆化數組 82 */ 83 void create_heap(int a[], int n) 84 { 85 int i; 86 for(i=n/2-1;i>=0;i--)/*將數組轉成堆,分開調整*/ 87 { 88 Heap_del_fix(a,i,n); 89 } 90 } 91 92 /* 93 *堆排序 94 */ 95 void Heap_sort(int a[],int n) 96 { 97 int i; 98 for(i=n-1;i>=1;i--) 99 { 100 swap(&a[0],&a[i]); 101 Heap_del_fix(a,0,i); 102 } 103 } 104 int main() 105 { 106 int i; 107 int a[] = {2,4,8,1}; 108 109 create_heap(a,4); 110 Heap_sort(a,4); 111 for(i=0;i<4;i++) 112 printf("%d ",a[i]); 113 printf("\n"); 114 system("pause"); 115 }
時間複雜度:
因爲每次從新恢復堆的時間複雜度爲O(logN),共N - 1次從新恢復堆操做,再加上前面創建堆時N / 2次向下調整,每次調整時間複雜度也爲O(logN)。二次操做時間相加仍是O(N * logN)。故堆排序的時間複雜度爲O(N * logN)。STL也實現了堆的相關函數,能夠參閱《STL系列之四 heap 堆》