堆的分析与实现(基于C语言)

一、堆的概念及性质结构

堆是一种非线性数据结构,本质上堆其实是一棵完全二叉树,通常存储在一维数组当中。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。
堆具有的性质:
1.堆总是一棵完全二叉树;
2.堆中某个节点的值总是不大于或不小于其父亲节点的值;

对第二点的理解是:当堆为大根堆时,堆的根节点的值一定大于或等于其两个孩子节点的值;当堆为小根堆时,堆的根节点的值一定小于或等于其两个孩子节点的值
在这里插入图片描述
在这里插入图片描述


二、堆的实现

堆的存储结构是顺序表,堆的实现紧紧围绕着两个核心算法,即向上调整算法与向下调整算法。下面将分别从向上调整算法与向下调整算法展开,借助对堆的功能实现示例来分析这两种算法。首先展示堆的结构定义:

//定义Heap结构体
typedef struct Heap
{
   
	int* a;
	int size;//顺序表的长度
	int capacity;//顺序表的容量
}HP;

1.向上调整算法

向上调整顾名思义即从下往上调整,从叶子节点开始向根节点的方向进行调整。

1)向上调整算法代码实现

基本的思想: (默认调整小堆)AdjustUp函数中形参child用来接收传入的孩子节点的下标,定义 parent变量来表示当前孩子的父亲节点的下标(由完全二叉树在数组中存储的性质得,parent=(child-1)/2 ,便可得到父亲节点的下标),通过比较 a[parent] 的值与 a[child] 的值,如果调整的是大堆则当
a[parent]>a[child] 时交换两值,如果调整的是小堆则当 a[parent] <a[child] 时交换两值。利用循环不断重复这一步骤,如果符合交换条件的就更新当前的childparent,再将parent的下标更新一下,直到child走到根节点时停止,或者是当交换条件不符合时停止循环。

代码示例如下:

//交换函数
void Swap(int* a, int* b)
{
   
    int tmp = *a;
    *a = *b;
    *b = tmp;
}

//a是存储堆的数组,child接收的是传入的孩子节点的下标
void AdjustUp(int* a, int child)
{
   
    //完全二叉树的性质
    int parent = (child - 1) / 2;

    while (child > 0)
    {
   
        //调整小堆    
        if (a[child] < a[parent])
        {
   
            //交换两值
            Swap(&a[child],&a[parent]);
            
            //继续向上调整
            child = parent;
            parent = (child - 1) / 2;
        }
        else
        {
   
            break;
        }
    }
}

2)堆的插入

堆的插入运用到的就是向上调整算法。因为堆的插入是从堆最后一个元素后插入,插入元素容易,但同时也要确保堆的结构不被破坏,因此要在插入以后再向上调整以保持堆的结构。

基本思想: 由于堆的存储结构是动态的顺序表,所以当进行插入操作时第一步是需要判断顺序表是否有容量能够插入,如果容量满了,则需要realloc出一个新的空间,进行扩容操作。进行插入操作只需要在顺序表尾部插入元素并且将元素个数size加一即可,需要注意的是,插入的数据可能不符合堆的结构,所以我们需要采用向上调整算法将插入后的结构重新调整为堆。

//以小堆为示例
void HeapPush(HP* php, int x)
  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

JJP1124

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

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

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

打赏作者

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

抵扣说明:

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

余额充值