您的位置:首页 > 理论基础 > 数据结构算法

数据结构与算法学习-堆排序

2016-11-10 18:56 435 查看
堆排序:

堆的标准定义如下:

n个元素的序列{k1, k2, …, kn}当且仅当满足以下关系时,称为堆。

(Ki<=K2i&&Ki<=K2i+1)或(Ki>=K2i&&Ki>=K2i+1)


(i = 1, 2, ..., n/2)


可以简单理解为就是一个完全二叉树,但是比较特殊,即完全二叉树中所有非终端结点的值均不大于(或不小于)其左、右孩子结点的值。

示例:



小顶堆:意思就是堆顶的值是最小的

大顶堆:意思就是堆顶的值是最大的

知道了堆的性质,我们自然可以推出怎么排序,首先需要把输入的数组构建成一个小顶堆/大顶堆,只需要每次把堆顶和无序的最后一个元素交换,然后更新堆,再交换,再更新。。。。就可以达到有序了。

具体步骤:

1. 先将输入的数据构建成小顶堆/大顶堆

2. 将堆顶a[1]和最后一个元素a[i]交换,i–

3. 更新堆,使其重新成为小顶堆/大顶堆

4. 一直重复第2步和第3步,直到i==1为止。

代码如下:

#include <iostream>
using namespace std;
#include <cstdio>
int min(int x, int y)
{
if(x < y)
return 0;
return 1;
}
void HeapAdjust(int a[], int s, int m) //调整堆,使其有序
{
int temp = a[s];
for(int j = 2*s; j <= m; j *= 2)
{
if(j < m && min(a[j+1], a[j]))
{
j++;
}
if(!min(a[j], temp))    break;
a[s] = a[j];
s = j;
}
a[s] = temp;
}
void HeapSort(int a[], int len)
{
for(int i = len/2; i > 0; --i)  //先将输入的乱序数组构建成堆,对应第1步
{
HeapAdjust(a, i, len);
}
for(int i = len; i > 1; --i)  //交换a[1]和a[i]的值,更新堆。对应第2,3步
{
int temp = a[1];
a[1] = a[i];
a[i] = temp;
HeapAdjust(a, 1, i-1);
}
}
int main()
{
int a[11] = {0};
for(int i = 1; i <= 10; i++)
{
scanf("%d", &a[i]);
}
HeapSort(a, 10);
for(int i = 1; i <= 10; i++)
{
printf("%d\n", a[i]);
}
return 0;

}


以该图为例:



第一步我们输入{13,38,27,49,76,65},希望输出升序排列,即{13,27,38,49,65,76}

第二步先构建成大顶堆。
HeapAdjust(a, 3, 6)
,比较27和65的大小,27<65,则两者互换。
HeapAdjust(a, 2, 6)
,比较49和76的大小,再将其中的较大者和38比较,于是76和38互换。
HeapAdjust(a, 1, 6)
,比较76和65的大小,再将其中较大者和13比较,于是76和13互换,此时的13比它的子结点小,于是又进行了一次互换,将49和38的较大者和13互换了。此时就得到了一个大顶堆。



第三步将76和27互换,
HeapAdjust(a, 1, 6-1)
,将65和49做比较,取较大者和a[1]的27交换,完成了第一次更新。将65和38互换位置,
HeapAdjust(a, 1, 5-1)
,由于38比它的子结点小,于是又要做交换,将49和38做交换,完成了第二次更新。将49和13互换位置,
HeapAdjust(a, 1, 4-1)
,38和27做比较,将较大者和13互换位置,即38和13互换,完成了第三次更新。将38和27互换位置,此时27就是最大元素了,完成了第四次更新。将27和13交换,此时只剩下13最后一个元素,完成了第五次更新,达到有序。



最后还有一点,堆排序适用于大文件,而不适用于小数据。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: