堆排序算法

算法:堆排序(Heap Sort)就是利用堆(假设利用大顶堆)进行排序的方法。它的基本思想是,将待排序的序列构造成-一个大顶堆。此时,整个序列的最大值就是堆顶的根结点。将它移走(其实就是将其与堆数组的末尾元素交换,此时末尾元素就是最大值),然后将剩余的n-1个序列重新构造成-一个堆, 这样就会得到n个元素中的次小值。如此反复执行,便能得到-一个有序序列了。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define MAXSIZE 20

typedef int data_t;

typedef struct{
    data_t data[MAXSIZE];
    int last;
}Seqlist_t;

Seqlist_t *seqlist_create() //创建顺序表
{
    Seqlist_t *S = (Seqlist_t *)malloc(sizeof(Seqlist_t));
    if(S == NULL)
    {
        perror("malloc");
        return NULL;
    }
    S->last = -1;
    return S;
}

int seqlist_insert(Seqlist_t *L,data_t x,int pos) //在顺序表中插入数值
{
    if(L == NULL)
        return -1;
    if(L->last == MAXSIZE-1 || pos<0 || pos>L->last+1)
        return -1;
    int i = 0;
    for(i=L->last; i>=pos; i--)
        L->data[i+1] = L->data[i];
    L->data[pos] = x;
    L->last += 1;
    return 0;
}
//将堆顶记录和当前未经排序子序列的最后一个记录交换
void seqlist_swap(Seqlist_t *L, int i, int j)
{
    int temp = L->data[i];
    L->data[i] = L->data[j];
    L->data[j] = temp;
}
//已知L->data[r. .l]中记录的关键字除L->data{r]之外均满足堆的定义
//本函数调整L->data[r]的关键字,使L->data[r..l]成为一个大顶堆
void seqlist_heapadjust(Seqlist_t *L,int r,int l)
{
    int i = 0;
    int temp = L->data[r];
    for(i=2*r; i<=l; i=i*2) //沿关键字较大的孩子结点向下筛选
    {
        if(i<l && L->data[i]<L->data[i+1])
            ++i;   //i为关键字中较大的记录的下标
        if(temp >= L->data[i])
            break; //data[i]应该插入在r位置上
        L->data[r] = L->data[i];
        r = i;
    }
    L->data[r] = temp;  //插入
}
//堆排序,对顺序表进行
void seqlist_heapsort(Seqlist_t *L)
{
    int i = 0;
    for(i=(L->last+1)/2; i>0; i--) //把L中的data[i]构建成大顶堆
        seqlist_heapadjust(L,i,(L->last+1));
    for(i=(L->last+1)/2; i>1; i--)
    {
        seqlist_swap(L,1,i);   将堆顶记录和当前未经排序子序列的最后一个记录交换
        seqlist_heapadjust(L,1,i-1); //将L->data[1..i-1]重新调整为大顶堆
    }
}

void seqlist_show(Seqlist_t *L) //对顺序表进行遍历
{
    if(L == NULL)
        return ;
    int i = 0;
    for(i=0; i<=L->last; i++)
        printf("%d ",L->data[i]);
    printf("\n");
}

int seqlist_length(Seqlist_t *L) //求顺序表的长度
{
    if(L == NULL)
        return -1;
    return (L->last+1);
}

int main(int argc, char *argv[])
{ 
    Seqlist_t *S = seqlist_create();
    srand(time(NULL));
    int i = 0;
    while(i < 15)
    {  //生成随机数10-150进行排序
        seqlist_insert(S,(i+1),rand()%(i+1));
        i++;
    }
    printf("befor sort:\n");
    seqlist_show(S);
    seqlist_heapsort(S);
    printf("after sort:\n");
    seqlist_show(S);

    return 0;
} 

运行结果:

156849c094744243aa085bf82dc721b4.png

堆排序复杂度:

它的运行时间主要是消耗在初始构建堆和在重建堆时的反复筛选上。

在构建堆的过程中,因为我们是完全二又树从最下层最右边的非终端结点开始构建,将它与其孩子进行比较和若有必要的互换,对于每个非终端结点来说,其实最多进行两次比较和互换操作,因此整个构建堆的时间复杂度为0(n)。

在正式排序时,第i次取堆顶记录重建堆需要用0(ogi)的时间(完全二叉树的某个结点到根结点的距离为Llog2i]+1),并且需要取n-1次堆顶记录,因此,重建堆;的时间复杂度为0(nlogn)。

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值