堆排序

堆排序,就是利用二叉堆的特性来完成排序的工作。

这里假定我们要完成对一个数组进行从小到大排序的工作,那么利用最小堆(见《二叉堆 - 最小堆》)的特性,对于一个已经建好的最小堆,我们每次以DeleteMin函数取出最小的元素,放入一个临时数组中,如此一来,就完成了对该数组的排序。时间复杂度的话,建立堆的过程可以是O(NlogN)或者O(N),看我们是以Insert函数建堆,还是以PercDown函数建堆。取出元素的DeleteMin函数,是O(logN),有N个元素,所以是O(NlogN)。所以时间复杂度为O(NlogN)。但是使用到了额外的临时数组,空间复杂度为O(N)。当待排序数组很大的时候,这一开销还是值得商榷的。

为了避免空间上的额外开销,我们注意到,当我们使用DeleteMin的时候,堆中最小的元素被拿走,最后一个位置的元素向上移动到合适的位置,那么就空出了最后一个位置。所以我们可以把最小的元素放在最后一个位置上。依此类推,在对N个元素进行DeleteMin之后,堆就表现出从大到小排序的数组的样子了。所以我们把堆序改成最大堆,使用DeleteMax,那么最后堆就表现出从小到大的排序数组。

另外,如果我们考虑用PercDown函数建堆,用DeleteMax函数来进行排序数组的输出,观察最大堆的实现(见《二叉堆 - 最大堆》),我们可以稍作调整,合并PercDown函数和DeleteMax函数,并且省略堆结构的初始化和建立,直接以数组的形态进行堆排序。

代码如下:

 1 #include <cstdio>
 2 #include <cstdlib>
 3 
 4 typedef int Item;
 5   
 6 void 
 7 Swap(Item* a, Item* b)
 8 {   if (a != b) {
 9     *a ^= *b;
10     *b ^= *a;
11     *a ^= *b;   }
12 }    
13 
14 // 跟前面最大(小)堆的程序不同,这里添加最后一个参数,用来控制边界 
15 void 
16 PercDown(Item arr[], int i, int len) 
17 {
18     int child;
19     Item tmp;
20     
21     for (tmp = arr[i]; 2*i+1 < len; i = child) {
22         child = 2 * i + 1;
23         if (child != len-1 && arr[child+1] > arr[child]) {
24             child++;
25         }
26         if (tmp < arr[child]) {
27             arr[i] = arr[child];
28         } else {
29             break;
30         }
31     }
32     arr[i] = tmp;
33 }
34 
35 void
36 HeapSort(Item arr[], int len)
37 {
38     int i;
39     // build maximum heap
40     for (i = len/2; i >=0; i--) {
41         PercDown(arr, i, len);
42     }
43     // delete maximum item
44     for (i = len-1; i > 0 ; i--) {
45         Swap(&arr[0], &arr[i]);
46         PercDown(arr, 0, i);
47     }
48 }
49   
50 
51 int 
52 main(int argc, char** argv)
53 {
54     Item arr[6] = {17, 11, 2, 23, 5, 7};
55     
56     HeapSort(arr, 6);
57     
58     for (int i = 0; i < 6; i++) {
59         printf("%d\t", arr[i]);
60     }
61     printf("\n");
62     
63     system("pause");
64     
65     return 0;
66 }

 

参考:Mark Allen Weiss《数据结构与算法分析——C语言描述》(第二版)

 

posted @ 2014-10-29 16:17  nipan  阅读(310)  评论(0编辑  收藏  举报