-
堆排序
简单介绍:具有空间原址性(即进行原址排序,任何时候都只需要常数个额外的元素空间存储临时数据)。二叉堆是一个数组,近似可以看成一个完全二叉树,可分为最大堆和最小堆。在堆排序中,采用的是最大堆,其性质是:除了根节点以外的所有节点i都满足父节点>子节点。而最小堆常用来构造优先队列。
时间复杂度:时间复杂度 Θ ( n lg n ) \Theta(n \lg n) Θ(nlgn) -
堆排序的伪代码(截图于算法导论)
a) max_heapify: 用于维护堆性质,其时间复杂度是 O ( lg n ) O(\lg n) O(lgn)
b) build_max_heap: 将输入数组构造成一个最大堆,其时间复杂度是线性的.
c) heap_sort: 对输入数组进行原址排序,其时间复杂度是 O ( n lg n ) O(n \lg n) O(nlgn)
-
C++实现(需要注意的是,C++数组的起始标号是0,而上述算法中数组的起始是1)
/**
堆排序 2020.04.20
Author: 豆奶
Reference: 算法导论第三版
**/
#include <iostream>
using namespace std;
/**
定义max_heapify函数去维护最大堆的性质,即保证父节点的值大于子节点的值
Input:
A[]: int[], 待排序的数组. 指针传递,函数内部对A的修改能导致外部A的变化
i: int, 需要维护堆性质的子堆.
length: int,是待排序数组的长度.
Output:
A: int*, 排序后的数组.
**/
void max_heapify( int A[], int i, int length){
int l = 2*i+1; // i的左子节点
int r = 2*i+2;
int largest; // i, l, r中,在A中值最大的索引
if (l<length && A[l]>A[i])
largest = l;
else
largest = i;
if (r<length && A[r]>A[largest])
largest = r;
// 如果最大那个数的索引不是i,则交换值使得i是最大值的索引
if (largest != i){
int temp = A[i];
A[i] = A[largest];
A[largest] = temp;
max_heapify(A, largest, length); // 对交换后的largest堆进行调整
}
}
/**
定义buidl_max_heap函数去建立最大堆
Input:
A[]:int[],是需要排序的数组.
length: int,是待排序数组的长度.
**/
void buidl_max_heap(int A[], int length){
for(int i = int(length/2)-1; i>=0; i--)
max_heapify(A, i, length);
}
/**
定义heap_sort函数实现堆排序
Input:
A[]:int[],是需要排序的数组.
length: int,是待排序数组的长度.
Output(不需要return):
A: int*, 排序后的数组.
**/
void heap_sort(int A[], int length){
buidl_max_heap(A, length);
for(int i=length-1; i>0; i--){
int temp = A[0];
A[0] = A[i];
A[i] = temp;
length = length -1;
max_heapify(A, 0, length);
}
}
- 测试
int main(){
int A[15] = {3, 19, 13, 5, 6, 28, 33, 38, 43, 12, 53, 58, 63, 2, 73};
int i;
cout<<"A[i]的值为: ";
for(i=0; i<15; i++){
cout<<A[i]<<", ";
}
cout<<endl;
int length = sizeof(A)/sizeof(A[0]);
//sizeof()函数可以返回数组所占的内存,而sizeof(A[0])返回的是数组第一个元素所占的内存。
heap_sort(A, length);
cout<<endl<<"排序后A[i]的值为: ";
for(i=0; i<15; i++){
cout<<A[i]<<", ";
}
cout<<endl<<endl;
return 0;
}
- 参考文献
- 算法导论(第三版)
- 麻省理工学院:算法导论 (视频)
如有不对之处,还望指出.