堆排序

排序有很多种方法,堆排序是其中的一种。它是选择排序的一种。可以利用数组的特点快速定位指定索引的元素。

堆有一个很好的性质:第i个位置上的值小于第2*i个位置上和第2*i+1个位置上的值(i<2*i && i<2*i+1),这种堆称为小根堆;第i个位置上的值大于第2*i个位置上和第2*i+1个位置上的值(i<2*i && i<2*i+1),这种堆称为大根堆。而第i个位置正好是第2*i个位置和2*i+1个位置的父母结点。

小根堆排序后是从大到小,大根堆排序后是从小到大。

我们先把准备工作做好

#include <stdio.h>
#include <stdlib.h>
#include<math.h>
#define MAX_SIZE 100
typedef char InfoType;
typedef struct Sz
{
    int key;
    InfoType *info;
}Sz;

typedef struct SQ//定义一个顺序线性表
{
    Sz *R;
    int length;
}SqList;

int Init_SqList(SqList *L)//顺序线性表初始化
{
    L->R=(Sz *)malloc((MAX_SIZE + 1) * sizeof(Sz)) ;
    if(!L->R)
        return 0;
    else
    {
        L->length = 0;
        return 1;
    }
}

要对一个数组进行堆排序,首先要建立一个堆。

void Heap_adjust(SqList *L, int s, int m)
{
    /*H->R[s…m]中记录关键字除H->R[s].key均满足堆定义*/
    /*调整H->R[s]的位置使之成为小根堆*/
    int j = s;//起始位置
    int k = 2 * j;/*计算H->R[j]的左孩子的位置*/
    L->R[0] = L->R[j];/*临时保存H->R[j]*/
    for (k = 2 * j; k <= m; )//k = 2*k
    {
        if(((k + 1) <= m) && (L->R[k].key > L->R[k + 1].key))
            k++;/*选择左、右孩子中关键字的最的一个*/

        if(L->R[k].key < L->R[0].key)
        {
            L->R[j] = L->R[k];
            j = k;
            k = 2 * j;
        }
        else
        {
            break;
        }
    }
    L->R[j] = L->R[0];
}

然后把第一个元素和最后一个元素交换,交换之后可能就把堆打乱了,所以要重新在建立一个堆。这样交换n-1次,数组就有序了。

void Heap_Sort(SqList *L)
{
    int i;
    int j;
    for(j = L->length/2; j > 0; j--)
        Heap_adjust(L, j, L->length);/*初始建堆*/


    for(j = 1; j <= L->length; j++)
    {
        printf("%d  ", L->R[j].key);
    }
    printf("\n");
    printf("------------------------------\n");

    int k = L->length;
    //需要进行n-1次交换
    for(j = k; j > 1; j--)
    {
        L->R[0] = L->R[1];
        L->R[1] = L->R[k];
        L->R[k] = L->R[0];/*堆顶与最后一个交换*/
        k--;/*每交换一次,长度减一,把最后一个元素除去*/
        printf("%d\n", k);
        if(j != 1)
        {
            for(i = ceil(k / 2); i > 0; i--)
                Heap_adjust(L, i, k);/*建堆*/
        }

        for(i = 1; i <= k; i++)
        {
            printf("%d  ", L->R[i].key);
        }
        printf("\n");
    }
}

主方法

int main()
{
    int i;
    int num;
    SqList L;
    Init_SqList(&L);
    /*输入数组*/
    printf("please enter the number of the data:");
    scanf("%d", &num);
    for(i = 1; i < num + 1; i++){
        int values;
        printf("please enter the %d data:", i);
        scanf("%d", &values);
        L.R[i].key = values;
        L.length++;
    }

    for(i = 1; i <= L.length; i++)
    {
        printf("%d  ", L.R[i].key);
    }
    printf("\n");

    printf("-------------create heap----------------\n");
    Heap_Sort(&L);

    printf("-------------after heap sort----------------\n");
    for(i = 1; i <= L.length; i++)
    {
        printf("%d  ", L.R[i].key);
    }
    printf("\n");
    return 0;
}

例:
这里写图片描述
运行结果:
这里写图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值