时间复杂度:O(nlgn) 与归并排序相同
最坏:O(nlgn)
空间复杂度:O(1).
不稳定。
堆的实现通过构造二叉堆(binary heap),实为二叉树的一种;由于其应用的普遍性,当不加限定时,均指该数据结构的这种实现。这种数据结构具有以下性质。
* 任意节点小于(或大于)它的所有后裔,最小元(或最大元)在堆的根上(堆序性)。
* 堆总是一棵完全树。即除了最底层,其他层的节点都被元素填满,且最底层尽可能地从左到右填入。
* 将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
如上图可以就是一个堆,数据结构可以视为一棵完全二叉树,数组表示如右图,假设该数组名为A。
如上图所示,树的根为A[1],若父节点为A[i],则其左子树下标为A[i/2],右子树下标为A[i/2+1]。
伪代码如此表示
PARENT(i)
return [i/2]
LEFT(i)
return 2i
RIGHT(i)
return 2i+1
* 注意:数组下标第一个是0,不是1 *
在堆排序算法中,使用的是最大堆,在最大堆中,最大堆性质是指除了根以外的所有接点i都满足A[PARENT(i)]>=A[i].
最小堆通常用于构造优先队列。
下面伪代码用于维护最大堆性质,称为MAX-HEAPIFY,输入一个数组A和一个下标i,调用MAX-HEAPIFY,假定其左右子树的二叉树都是最大堆,这个时候A[i]有可能小于其孩子,违背最大堆性质。此代码将A[i]的值在最大堆中逐级下降,使重新遵循最大堆性质。
简而言之,上面代码就是将当前结点与比他大的最大的子结点交换,并如此递归,当然,如果两个子结点都比他小,就不用交换了。
执行的过程如下图,堆i=2执行
既然知道如何维护堆的性质后,那么接下来就是把要排序的东东建堆了
思想 : 自底向上维护最大堆性质,那么我们就可以获得一个从根节点开始的最大堆
伪代码 :
经过上面的一些步骤,我们已经把最大的数字放到了根节点,那接下来我们只需要一次取出根结点,然后维护堆的性质(这时候剩根节点又是剩下的最大值),就可以获得一个排序好的数组啦。
这里,我们每次使用没排序的最后的节点替换根节点,伪代码如下
/*************************************************************************
> File Name: heap_sort.cpp
> Author: chunquanL
> Created Time: 2017-04-19
************************************************************************/
#include
#include
#define PARENT(i) (((i)-1)/2)
#define LEFT(i) ((i)*2+1)
#define RIGHT(i) ((i)*2+2)
void swap(int *a,int *b)
{
*a^=*b;
*b^=*a;
*a^=*b;
}
//维护最大堆性质函数
void max_heapify(int arr[],int len,int i)
{
int l = LEFT(i);
int r = RIGHT(i);
int max = i;
if(larr[max])
max=l;
if(rarr[max])
max=r;
if(max!=i)
{
swap(&arr[i],&arr[max]);
max_heapify(arr,len,max);
}
}
//堆排序函数
void heap_sort(int arr[],int len)
{
//1.建堆
for(int i=PARENT(len-1);i>=0;--i)
{
max_heapify(arr,len,i);
}
//2.排序
for(int i=len-1;i>0;--i)
{
swap(&arr[0],&arr[i]);
max_heapify(arr,i,0);
}
}
int main()
{
int arr[]={3, 5, 3, 0, 8, 6, 1, 5, 8, 6, 2, 4, 9, 4, 7, 0, 1, 8, 9, 7, 3, 1, 2, 5, 9, 7, 4, 0, 2, 6 };
int len=sizeof(arr)/sizeof(arr[0]);
for(int i=0;iprintf("%d ",arr[i]);
printf("\n");
heap_sort(arr,len);
for(int i=0;iprintf("%d ",arr[i]);
printf("\n");
}
/*************************************************************************
> File Name: heap_sort2.cpp
> Author: chunquanL
> Created Time: 2017-04-19
************************************************************************/
#include
#include
#define PARENT(i) (((i)-1)/2)
#define LEFT(i) ((i)*2+1)
#define RIGHT(i) ((i)*2+2)
void swap(int *a,int *b)
{
*a^=*b;
*b^=*a;
*a^=*b;
}
void max_heapify(int arr[],int start,int len)
{
int l,r,max;
while(LEFT(start)//左子树在边界范围内,说明非叶子结点 继续
{
l=LEFT(start);
r=RIGHT(start);
max = start;
if(larr[max])
max = l;
if(rarr[max])
max = r;
if(max!=start) //若此条件成立 则max为左右子树中的一个
{
swap(&arr[max],&arr[start]);
start = max;
}
else //不成立,已满足特性,退出
break;
}
}
void heap_sort(int arr[],int len)
{
//1.建堆
for(int i=PARENT(len-1);i>=0;--i)
{
max_heapify(arr,i,len);
}
//2.排序
while(--len)
{
swap(&arr[0],&arr[len]);
max_heapify(arr,0,len);
}
}
int main() {
int arr[] = { 3, 5, 3, 0, 8, 6, 1, 5, 8, 6, 2, 4, 9, 4, 7, 0, 1, 8, 9, 7, 3, 1, 2, 5, 9, 7, 4, 0, 2, 6 };
int len = (int) sizeof(arr) / sizeof(*arr);
heap_sort(arr, len);
int i;
for (i = 0; i < len; i++)
printf("%d ", arr[i]);
printf("\n");
return 0;
}