算法导论---第6章---堆排序
1、堆排序简介
堆排序(heapsort)。与归并排序一样,但不同于插入排序的是,堆排序的时间复杂度是O(nlgn)。而与插入排序相同,但不同于归并排序的是,堆排序同样具有空间原址性:任何时候都只需要常数个额外的元素存储临时数据。因此,堆排序是集合了插入排序和归并排序这两种排序算法优点的一种排序算法。
2、基本过程
MAX-HEAPIFY过程:其时间复杂度为O(lgn),它是维护最大堆性质的关键。
BUILD-MAX-HEAP过程:具有线性时间复杂度,功能是从无序的输入数据数组中构造一个最大堆。
HEAPSORT过程:其时间复杂度为O(nlgn),功能是对一个数组进行原址排序。
3、算法描述
首先,堆排序算法利用BUILD-MAX-HEAP将输入数组A[1...n]建成最大堆,其中n=A.length。因为数组中的最大元素总在根节点A[1]中,通过把它与A[n]进行互换,我们可以让该元素放到正确的位置。这时候,如果我们从堆中去掉节点n(这一操作可以通过减少A.heap-size的值来实现),剩余的节点中,原来根的孩子节点仍然是最大堆,而新的根节点可能会违背最大堆的性质。为了维护最大堆的性质,我们要做的是调用MAX-HEAPIFY(A, 1),从而在A[1...n-1]上构造一个新的最大堆。堆排序算法会不断重复这一过程,知道堆得大小从n-1降到2.
算法伪代码描述如下:
PARENT(i)
1 return ⌊i/2⌋
LEFT(i)
1 return 2i
RIGHT(i)
1 return 2i+1
MAX-HEAPIFY(A, i)
1 l = LEFT(i)
2 r = RIGHT(i)
3 if l ≤ A.heap-size and A[l] > A[i]
4 largest = l
5 else largest = i
6 if r ≤ A.heap-size and A[r] > A[largest]
7 largest = r
8 if largest ≠ i
9 exchange A[i] with A[largest]
10 MAX-HEAPIFY(A, largest)
BUILD-MAX-HEAP(A)
1 A.heap-size = A.length
2 for i = ⌊A.length/2⌋ downto 1
3 MAX-HEAPIFY(A, i)
HEAPSORT(A)
1 BUILD-MAX-HEAP(A)
2 for i = A.length downto 2
3 exchange A[1] with A[i]
4 A.heap-size = A.heap-size - 1
5 MAX-HEAPIFY(A, 1)
4、算法代码(C++实现)
ps:因为伪码中数组A的起始小标为1,而实际编写C++代码中,数组的起始下标为0,所以这里要注意计算父节点、子节点的下标公式与伪码中不同,同时需要注意循环体的结束条件也与伪码中略有差异。
1 #include <iostream> 2 #include <math.h> 3 #include <stdio.h> 4 5 using namespace std; 6 7 /* 8 #define PARENT(i) floor(i) 9 #define LEFT(i) 2*i 10 #define RIGHT(i) (2*i+1) 11 */ 12 13 inline int PARENT(int i) {return (i+1)/2 - 1;}; 14 inline int LEFT(int i) {return 2*i+1;}; 15 inline int RIGHT(int i) {return (2*i+2);}; 16 17 void Max_Heapify(int *a, int length, int i); 18 void Max_BuildHeap(int *a, int length); 19 void Max_HeapSort(int *a, int length); 20 21 int main() 22 { 23 int a[] = {4, 1, 3, 2, 16, 9, 10, 14, 8, 7}; 24 int length = 10; 25 26 Max_HeapSort(a, length); 27 28 cout << "Result of Max_HeapSort(): " << endl; 29 for (int i = 0; i < length; i++) 30 { 31 cout << a[i] << " "; 32 } 33 cout << endl; 34 35 return 0; 36 } 37 38 39 void exchange(int &a, int &b) 40 { 41 // 交换变量 a 和 b 的值 42 if (a == b) 43 { 44 return; 45 } 46 int tmp = a; 47 a = b; 48 b = tmp; 49 } 50 51 void Max_Heapify(int a[],int length, int i) 52 { 53 // 对数组 a 的第 i 个元素进行堆化操作 54 if (a == NULL) 55 { 56 cerr << "Max_Heapify(): Array is NULL!" << endl; 57 return; 58 } 59 int heap_size = length; 60 61 int l = LEFT(i); 62 int r = RIGHT(i); 63 int largest; 64 65 if (l < heap_size && a[l] > a[i]) 66 { 67 largest = l; 68 } 69 else 70 { 71 largest = i; 72 } 73 if (r < heap_size && a[r] > a[largest]) 74 { 75 largest = r; 76 } 77 if(largest != i) 78 { 79 exchange(a[i], a[largest]); 80 Max_Heapify(a, length, largest); 81 } 82 } 83 84 void Max_BuildHeap(int a[], int length) 85 { 86 // 建立最大堆 87 if (a == NULL) 88 { 89 cerr << "Max_BuildHeap(): Array is NULL!" << endl; 90 return; 91 } 92 for (int i = floor((length-1)/2); i >= 0; i--) 93 { 94 Max_Heapify(a, length, i); 95 } 96 } 97 98 void Max_HeapSort(int a[], int length) 99 { 100 // 最大堆排序 101 if (a == NULL) 102 { 103 cerr << "Max_HeapSort(): Array is NULL!" << endl; 104 return; 105 } 106 int heap_size = length; 107 Max_BuildHeap(a, length); 108 109 cout << "Result of Max_BuildHeap(): " << endl; 110 for (int i = 0; i < length; i++) 111 { 112 cout << a[i] << " "; 113 } 114 cout << endl; 115 116 for (int i = length-1; i >= 1; i--) 117 { 118 exchange(a[0], a[i]); 119 heap_size -= 1; 120 Max_Heapify(a, heap_size, 0); 121 } 122 }
运行结果如下: