經典算法系列三----堆排序

花了些時間好好看了堆排序的內容,代碼也敲了,如今來總結一下。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 堆

相關文章
相關標籤/搜索