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

来源:互联网 发布:教师资格考试软件下载 编辑:程序博客网 时间:2024/06/05 03:29

堆排序:
堆的标准定义如下:
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最后一个元素,完成了第五次更新,达到有序。

最后还有一点,堆排序适用于大文件,而不适用于小数据。

0 0
原创粉丝点击