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