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

花了些时间好好看了堆排序的内容,代码也敲了,如今来总结一下。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 堆

相关文章
相关标签/搜索