堆,是在逻辑上模仿完全二叉树的一维数组,(假设数组开始下标为0)某父节点 i 其左右孩子可以表示为2*i+1(左)和2*i+2(右).
堆排序的思想是每次从堆顶拿出一个元素(最大或最小取决于是大顶堆还是小顶堆)放入已排序数组,然后将堆最后一个元素插入堆顶,
这样将引起堆的不平衡,然后重新调整堆至平衡,重复做下去。注意,每次拿出堆顶元素堆的大小都会减小1.
关于堆的复杂度:
排序算法 | 平均时间复杂度 | 最坏时间复杂度 | 最好时间复杂度 | 空间复杂度 | 稳定性 | 复杂性 |
堆排序 | O(nlgn) | O(nlgn) | O(nlgn) | O(1) | 不稳定 | 较复杂 |
#include <stdio.h>
#include <stdlib.h>
#define size 10 /*数组大小*/
#define lchild(i) (2*i+1) /*数组起始下标为0,其左孩子为2*i+1 */
#define swap(a,b) {a^=b;b^=a;a^=b;} /*两个元素交换*/
/*调整堆平衡的函数*/
void heap_adjust(int *arr,int start,int end)
{
int temp = arr[start];
int i;
for(i = lchild(start); i <= end; i*=2){
/*获得两个孩子中较大的一个,如果右孩子大于左孩子,则
*i下标增加为右孩子下标,否则不变
*/
if(i<end && arr[i]<arr[i+1]){
i++;
}
/*比较父亲和孩子中较大的*/
if(temp > arr[i]){
break;
}
/*孩子比父亲大,孩子上位取代父亲*/
arr[start] = arr[i];
/*以孩子的位置进行下一次调整*/
start = i;
}
/*插入最开始引起堆不平衡的元素*/
arr[start] = temp;
}
/*堆排序主程序*/
void heap_sort(int *arr,int n)
{
int i;
/*创建大顶堆,从最后一个非叶子节点开始,自
*下而上调整。
*/
for(i = n/2;i>=0;i--){
heap_adjust(arr,i,n-1);
}
/*堆排序。每次将堆顶元素与堆的最后一个叶子节点交换
*交换后堆不平衡,重新调整堆,每交换一次,要调整堆
*的大小减小一个
*/
for(i=n -1;i > 0;i--){
swap(arr[0],arr[i]);
heap_adjust(arr,0,i-1);
}
}
int main()
{
int arr[size]={1,3,4,7,13,-1,8,2,6,0};
heap_sort(arr,size);
int i;
for(i = 0;i<size;i++){
printf("%d ",arr[i]);
}
return 0;
}