您的位置:首页 > 其它

堆排序-Heap Sort

2017-09-22 11:29 344 查看
坐在宿舍敲代码,楼下大一新生在军训

当初我们整齐的口号,嘹亮的军歌

是否也触动了哪位老学长

有人来,就得有人走,

人来人往,这样的更迭交替

不过是毅种循环

什么是堆?

堆一棵二叉树,其子结点的值通常都小(大)于父结点。根结点是树中的最大(小)结点,其中,子结点比父结点小的堆称为最大值堆,相反的被称为最小值堆。对与一个堆,我们可以用层序遍历的方式将它连续储存在一个数组中。



我们发现了一个规律:堆的左孩子和右孩子在数组中对应的下标分别为2i+1和2i+2。

堆排序

我们可以利用堆的特点来完成排序,对于一个最大值堆,其根结点总是最大的,把根结点拿出来放到数组最后一个位置,然后再把数组前面的元素重新调整为最大值堆,如此反复执行直到排序结束。

代码如下:

void max_heap(int *arr,int start,int end)//调整为一个最大值堆
{
int i,j,tmp;
i = start,tmp = arr[i];

for(j=2*i+1; j<=end; j*=2)
{
while(j<end && arr[j]<arr[j+1])//让j指向左孩子和右孩子中大的那个
j++;

if(tmp >= arr[j])
break;
else
{
arr[i] = arr[j];
arr[j] = tmp;
}
i = j;
}
}

void heap_sort(int *arr,int sz)
{
int i;
for(i=sz/2-1; i>=0; i--) //调整数组为最大值堆
max_heap(arr,i,sz-1);

for(i=sz-1; i>0; i--)//拿出根结点放到最后位置,然后进行调整
{
int tmp = arr[0];
arr[0] = arr[i];
arr[i] = tmp;
max_heap(arr,0,i-1);
}

}

int main()
{
int i;
int arr[] = {76,32,14,86,40,98,18,57,13,20,85};
int sz = sizeof(arr)/sizeof(arr[0]);

heap_sort(arr,sz);

for(i=0; i<sz; i++)
printf("%d ",arr[i]);
return 0;
}


下面是对于数组arr[] = {76,32,14,86,40,98,18,57,13,20,85};进行堆排序的过程:

整个逻辑分为两个部分:

第一部分,先将数组转化为最大值堆:

初始:i= sz/2-1,即i=4;



上面是用max_heap(arr,4,10)把arr[4…10]调整为最大堆 ,即把arr[4]和它两个孩子(arr[9]和arr[10])中较大值进行交换。

i=3时,父节点87比57和13都大,因此不交换。

i=2时,14和98交换。

i=1时,32和86交换。

i=0时,76和98交换。

此过程完成后 , 数组变成了一个最大值堆。如下图:



第二部分,进行数据交换,把最大堆数组变为有序数组

先把数组第一个元素(根结点)和最后一个元素交换



交换后:



交换完成后,对于arr[10],我们就不要再理它了,孤立它,把arr[0….9]调整为最大堆:



当n=9时,孤立86,调整arr[0…8],此时arr[9..10]是有序的

...

...

依次类推,直到整个数组有序。

堆排序的时间复杂度为O(nlgn),并且堆排序不是稳定的算法。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  堆排序 二叉树 遍历