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

1.堆

堆的逻辑结构是一颗完全二叉树
堆的物理结构是一个顺序表
通过下标去实现父子节点关系

leftchild=parent*2+1
rightchild=parent*2+2
parent=(child-1)/2;

就类似于下图
在这里插入图片描述
在这里插入图片描述

2.堆的两个特性

大堆:所有父亲大于等于孩子
小堆:所有父亲小于等于孩子
结构性:用数组表示的完全二叉树
有序性:任意结点的关键字是其子树所有结点的最大值(或最小值)
最大堆”也称“大堆顶”:最大值
最小堆”也称“小堆顶”:最小值
在这里插入图片描述

3 .向下调整算法(以大堆为例)

//向下调整算法(左右子树必须是大堆)
void AdjustDown(int*a,int n,int root)
{
    int parent=root;
    int child=parent*2+1;
    while(child<n)
    {
        if( child+1<n && a[child+1]>a[child])
        {
            child+=1;
        }
        if(a[child]>a[parent])
        {
            Swap(&a[child],&a[parent]);
            parent=child;
            child=parent*2+1;
        }
        else
        {
            break;
        }
    }

}
那么左右子树不是小堆,就不能直接使用向下调整算法了,怎么办
可以倒着从最后一颗子树开始调
从最后一个非叶子结点开始调,最后一个非叶子节点的下标是(n-1-1)/2                      
		for(i=(n-2)/2;i>=0;i--)
    {
        AdjustDown(arr,n,i);
    }

2.排序

如果我们要给数组排升续,那么我们需要建大堆
每一次向下调整都可以找出一个最大的数放在第一个位置,
我们可以把第一个和最后一个交换,然后把最后一个数(也就是找出的那个最大的数)不看作
前n-1个数,继续向下调整,选出次大的数,再跟倒数第二个位置交换,后面过程以此类推。
到最后就可以完成排序。
在这里插入图片描述

在这里插入图片描述

 //建堆O(n)
 for(i=(n-2)/2;i>=0;i--)
 {
     AdjustDown(arr,n,i);
 }
 //排升序,建大堆
 int end=n-1;
 while(end>0)
 {
     Swap(&arr[0],&arr[end]);
     AdjustDown(arr,end,0);
      end--;
 }

4.完整代码

//交换两个数函数的分装
void Swap(int*x,int*y)
{
    int temp=*x;
    *x=*y;
    *y=temp;
}
//向下调整算法(左右子树必须是大堆)
void AdjustDown(int*a,int n,int root)
{
    int parent=root;
    int child=parent*2+1;
    while(child<n)
    {
        if( child+1<n && a[child+1]>a[child])
        {
            child+=1;
        }
        if(a[child]>a[parent])
        {
            Swap(&a[child],&a[parent]);
            parent=child;
            child=parent*2+1;
        }
        else
        {
            break;
        }
    }

}
#include<stdio.h>
int main()
{
    int i=0;
    int arr[]={10,9,8,7,6,5,4,3,2,1};
    int n=sizeof(arr)/sizeof(arr[0]);
    //建堆O(n)
    for(i=(n-2)/2;i>=0;i--)
    {
        AdjustDown(arr,n,i);
    }
    //排升序,建大堆
    int end=n-1;
    while(end>0)
    {
        Swap(&arr[0],&arr[end]);
        end--;
        AdjustDown(arr,end,0);
    }
    for(i=0;i<n;i++)
    {
        printf("%d ",arr[i]);
    }
    return 0;
}

5.时间复杂度的计算

用n表示元素个数
向下调整算法 ,最多向下调整高度(二叉树高度)次。
h=log(n);
所以一次向下调整的时间复杂度是log(n)
建堆的时间复杂度
T(n)=1*(h-1)+ 2* (h-2)+ 4* (h-3)+…2^(h-2)

T(n)= -h+2^h-1

建堆的时间复杂度就约等于O(N)

整体的时间复杂度O(N*logN)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

binary~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值