数据结构——排序(Part3:堆排序)

(图源:大话数据结构)

好文分享:排序算法解析:https://blog.csdn.net/kexuanxiu1163/article/details/103051357 

目录

0准备工作

1堆 

2堆排序算法


0准备工作

保存排序内容的自定义结构体,其中顺序表的长度,不算哨兵(下标为零的部分)

#define MAX 10
typedef struct SqlistData
{
    int r[MAX+1];//把r[0]空出来当哨兵或者临时变量
    int length;//记录长度,因为0被空出来了,所以长度和下标此时统一了

}SqList;

交换接口

void swap(SqList * L,int i,int j)//交换
{
    int temp = L->r[i];
    L->r[i] = L->r[j];
    L->r[j] = temp;
}

打印接口

void print(SqList * L)
{
    qDebug()<<"开始打印";
    for(int i = 1;i<=L->length;++i)
    {
        qDebug()<<L->r[i];
    }
}

顺序表的储存结构如下:

扫描二维码关注公众号,回复: 10148705 查看本文章

                           

零位下标什么也不储存,所以无论是遍历还是排序,都是从下标1开始,顺序表长度为5,小标和顺序表中的元素序号完全一致。

1堆 

                        

堆: 具有以下性质的完全二叉树:每个结点的值都大于或等于其左右孩子结点的值,成为大顶堆,如图1

或者每个结点的值都小于或等于其左右孩子结点的值,称为小顶堆

下面是很重要的关于完全二叉树的性质: 

                 

                           

2堆排序算法

                

                             

综上可以看出,要比就要比到叶子结点

void HeapSort(SqList * L)
{
    int i;
    for(i=L->length/2;i>0;i--)
        HeapAdjust(L,i,L->length);
    for(i = L->length;i>1;i--)
    {
        swap(L,1,i);
        HeapAdjust(L,1,i-1);
    }
    
}

整体思路非常清晰:

  1. 构建一个大顶堆
  2. 将最大值放在顺序表末尾swap(L,1,i),i从L->length开始
  3. 之后将剩余的数字调整为一个大顶堆

从上面的程序显然能看出这一点:

首先是构建一个大顶堆        HeapAdjust(L,i,L->length);

该接口后续后介绍,第二个参数是根结点的编号,第三个参数是末尾结点的编号

第二步:将已经变成大顶堆的首号(1)和末尾号进行交换

之后,最大的数字目前已经在末尾了

将剩余的数字,继续变成一个大顶堆,        HeapAdjust(L,1,i-1);
第二个参数是i-1,外侧一直如此循环,直到编号为2,进行最后一次排序。

下面介绍将普通顺序表变成大顶堆的接口函数:

void HeapAdjust(SqList * L,int s,int m)
{
    int temp,j;
    temp = L->r[s];
    for(j = 2*s;j<=m;j*=2)//从根的左孩子开始,从上到下,遍历所有的左孩子,知道左叶子结点(j>m)
    {
        if(j<m&&L->r[j]<L->r[j+1])//选出左右孩子中最大的
            ++j;
        if(temp>=L->r[j])//根比最大的都大,那不操作
            break;
        L->r[s] = L->r[j];//将大的放到根的位置
        s = j;//记录下谁替换了根,新的左孩子,也是下一个循环新的根
    }
    L->r[s] = temp;//最后将比较完的部分替换回去
}

接口需要输入三个参数:第一个,顺序表地址,第二个,根结点编号,第三个,尾部截止编号

根据堆的性质,根结点为s,左孩子就是2s,右孩子就是2s+1,当然了前提是2s和2s+1都小于M,也就是树的末尾结点编号

程序从根结点的左孩子入手,先比较该根结点的左右孩子谁大,之后比较这个最大的孩子和根的值谁大,谁大谁做根

然后左孩子是叶子结点函数还是其他,则需继续循环,下面是图文解释: 

(图源:大话数据结构) 

 

 

               

具体操作:

    SqList Data3 = {{0,50,10,90,30,70,40,80,60,20},9};
    print(&Data3);
    HeapSort(&Data3);
    qDebug()<<"简单的选择排序后";
    print(&Data3);

输出:

 

                          

发布了85 篇原创文章 · 获赞 11 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_41605114/article/details/104823405