堆排序一直没有搞的很明白!今天总算搞定了。其实核心在于“堆的调整”。接口形如adjust_heap(*p, int n, int i),一个T类型的,长度为n的数组,将以i为根节点的子树调整为大顶堆或者小顶堆。原理可以这么想:根节点T[i]有左孩子T[2*i+1]和右孩子T[2*i+2],假如左孩子已经是一个大顶堆,右孩子也是大顶堆,而且:
T[i] > T[2*i+1]
T[i] > T[2*i+2]
那么,根据堆的定义,T[i]就是一个大顶堆了。
堆排序首先定义了这么一个“堆的调整”操作,随后的算法都是基于此的。堆以数组存储,a[N],最后一个元素为a[N-1],其父节点为a[(N-1-1)/2],将a[(N-1-1)/2]调整为大顶堆,然后向前走,将a[(N-1-1)/2-1]、a[(N-1-1)/2-2]、。。。a[2]、a[1]、a[0]调整为大顶堆。最后整个数组是一个大顶堆。
随后删除元素。删除堆顶,将a[0]与最后一个元素a[N-1]交换,此时a[N-1]为最大值,随后对a[0]至a[N-2]范围的元素做“堆的调整”操作,调整为堆后,又删除堆顶,得到第二大的元素。。。。最后数组呈现递增排列。
所谓“堆的调整”就是,左孩子和右孩子都已经是堆了,根节点是新来的,此时需要自上而下调整一遍。
复杂度:一次堆的调整为log(n),建堆需要n Log(n)。删除元素为O(1),重新调整N次,复杂度也是n*log(n),最终复杂度为n*log(n)。
// 堆排序
// 堆的调整、建堆、删除
#include <stdio.h>
#include <stdlib.h>
template<typename T>
int is_heap(T *tp, int nLen);
template<typename T>
void adjust_heap(T *tp, int nLen, int pos);
template<typename T>
void make_heap(T *tp, int nLen);
template<typename T>
void heap_sort(T *tp, int nLen);
const int N=20;
int main()
{
int ap[N];
int i;
for (i=0;i<N;i++)
{
ap[i]=rand()%100;
printf("%d ", ap[i]);
}
printf("\n");
heap_sort(ap,N);
printf("排序后:\n");
for (i=0;i<N;i++)
{
printf("%d ", ap[i]);
}
printf("\n");
return 0;
}
//----------------------------------------
// 交换元素
template<typename T>
void _swap(T &a, T&b)
{
T tmp;
tmp=a;
a=b;
b=tmp;
}
// 堆的调整
template<typename T>
void adjust_heap(T *tp, int nLen, int pos)
{
int i=pos;
int j=2*i+1;
for ( ;j<nLen; )
{
if (j+1<nLen && tp[j+1]<tp[j])
j++;
if (tp[i] < tp[j])
{
break;
}
_swap(tp[i], tp[j]);
i=j;
j=2*j+1;
}
}
// 建堆
template<typename T>
void make_heap(T *tp, int nLen)
{
int i;
for (i=(nLen-1-1)/2; i>=0; i--)
{
adjust_heap(tp, nLen, i);
}
if (is_heap(tp,nLen))
{
printf("IS a HEAP\n");
}else
{
printf("NOT a HEAP\n");
}
}
// 排序
template<typename T>
void heap_sort(T *tp, int nLen)
{
make_heap(tp, nLen);
int i;
for (i=nLen-1; i>=1; i--)
{
_swap(tp[0], tp[i]);
adjust_heap(tp, i, 0);
}
}
// 判断是否为堆
template<typename T>
int is_heap(T *tp, int nLen)
{
int i;
for (i=0; 2*i+1<nLen; i++)
{
if (tp[i]>tp[2*i+1])
return 0;
if (2*i+2<nLen && tp[i]>tp[2*i+2])
return 0;
}
return 1;
}
ref:
http://blog.youkuaiyun.com/fly_yr/article/details/8550701
http://blog.sina.com.cn/s/blog_5115d58c0100vr26.html