第八章:堆的讲解与实现
创始人
2024-02-10 16:44:55
0

第八章:堆的实现与堆相关的算法

  • 一、堆
    • 1、什么是堆?
    • 2、堆的实现
      • (1)堆的定义
      • (2)接口函数
        • 初始化
        • 销毁
        • 插入
        • 删除
        • 判断是否为空
        • 返回堆顶
        • 返回堆中的元素个数
        • 打印

一、堆

1、什么是堆?

在前面的章节中,我们了解到了树、二叉树等相关的概念,那么今天所讲解的堆就是基于二叉树中的完全二叉树实现的。那么在完全二叉树的基础上,堆还满足该性质:堆中的子节点始终小于等于(大于等于)父节点。

倘若,堆的父节点始终小于等于其子节点,我们就称之为小根堆
倘若,堆的父节点始终大于等于其子节点,我们就称之为大根堆

堆的逻辑结构及物理结构;

在这里插入图片描述

从上述的物理结构我们可以知道,我们接下来的代码实现是基于数组的。因此,我们将采用动态顺序表的思路来存储堆。

2、堆的实现

(1)堆的定义

typedef int ElementType;
typedef struct Heap
{ElementType* a;int size;int capacity;
}Heap;

(2)接口函数

初始化

void HeapInit(Heap* h)
{assert(h);h->a=NULL;h->size=h->capacity=0;
}

销毁

void HeapDestory(Heap* h)
{assert(h);free(h->a);h->a = NULL;h->size = h->capacity = 0;
}

插入

因为我们是在数组中实现堆的,但是数组在中部插入的时间复杂度是O(N),头部插入的时间复杂度也是O(N)。因此,我们是在最后一个位置插入一个数据,然后再让这个数据向上移动。但是我们新插入的节点如何向前移动?

在下面的小根堆中,我们假设在尾部插入一个1。
在这里插入图片描述
从图中我们能够看出,我们将一个数据向上进行调整的时候,我们只需要关注该节点所在的路径。我们不妨把这条线抽离出来:
在这里插入图片描述
此时,我们发现,1需要向上移动的话,只需要和1的祖宗们相比较。因此,我们可以写出AdjustUp的函数。

void AdjustUp(Heap* h, int child)
{assert(h);while (child>0){int parent = (child - 1) >> 1;if (h->a[child] < h->a[parent]){ElementType tmp = h->a[child];h->a[child] = h->a[parent];h->a[parent] = tmp;child = parent;}else{break;}}
}void HeapPush(Heap* h,ElementType x)
{assert(h);if (h->size == h->capacity){size_t newcapacity = (h->capacity == 0) ? 4 : 2 * h->capacity;ElementType* tmp = realloc(h->a,sizeof(ElementType)*newcapacity);if (tmp == NULL){printf("realloc fail\n");exit(-1);}h->a = tmp;h->capacity = newcapacity;}h->a[h->size] = x;h->size++;AdjustUp(h,h->size-1);
}

当我们调整好后,就会出现下面的样子:
在这里插入图片描述

删除

在插入函数的铺垫下,这里讲解删除就好理解多了。我们的堆删除的元素一般是堆顶元素。因此,我们这里需要删除的是堆顶。但数组中删除堆顶元素的时间复杂度是O(N)。这是相当复杂的,而尾删的时间复杂度是O(1),于是我们这里也是先将尾部元素和堆顶元素进行交换,然后再将堆顶元素向下移动。
在这里插入图片描述
但是我们这里要解释一下:为什么要和子结点中较小的交换。
在这里插入图片描述
通过上述反例,我们就发现了根节点和较小子节点交换的重要性。

void AdjustDown(Heap* h, int parent)
{assert(h);int child = parent * 2 + 1;while (childsize){if (child + 1 < h->size && h->a[child + 1] < h->a[child]){child++;}if (h->a[child] < h->a[parent]){ElementType tmp = h->a[child];h->a[child] = h->a[parent];h->a[parent] = tmp;parent = child;child = parent * 2 + 1;}else{break;}}
}void HeapPop(Heap* h)
{assert(h);assert(!HeapEmpty(h));ElementType tmp = h->a[0];h->a[0] = h->a[h->size - 1];h->a[h->size - 1] = tmp;h->size--;AdjustDown(h,0);
}

判断是否为空

bool HeapEmpty(Heap* h)
{assert(h);return h->size == 0;
}

因为我们在C语言中本身是没有bool的,所以我们需要包含头文件

返回堆顶

这里要注意一下,返回之前我们要判断堆是否为空。

ElementType HeapTop(Heap* h)
{assert(h);assert(!HeapEmpty(h));return h->a[0];
}

返回堆中的元素个数

int HeapSize(Heap* h)
{assert(h);return h->size;
}

打印

void HeapPrint(Heap* h)
{assert(h);for (int i = 0; i < h->size; i++){printf("%d ",h->a[i]);}printf("\n");
}

这里我们需要注意是,打印出来的是一个数组,因此,我们要根据完全二叉树的下标之间的规律去还原堆的逻辑结构。

相关内容

热门资讯

外汇局揭阳市分局联合多部门举办... 为加强宣导外贸企业汇率“风险中性”理念,畅通外汇业务政策渠道,助力企业在对外贸易中行稳致远,更好支持...
海伦哲:公司严格按照相关法律法... 证券之星消息,海伦哲(300201)07月03日在投资者关系平台上答复投资者关心的问题。 投资者提问...
龙宇股份603003终止上市,... (本文部分辑自“金融法律实务评论”微信公众号:touzifalv,涉及文章内容交流或咨询请关注公众号...
安徽黄山:双政策加码让续贷“无... “比过桥减少近6万元成本,这笔节省下来的钱又可以投入后续民宿升级改造,而且无还本续贷手续很便捷。现在...
@赛力斯汽车法务部 因违反相关... 7月4日,据东方财经查询发现,赛力斯汽车法务部官方微博账号显示“因违反相关法律法规,该用户目前处于禁...
送到《长安的荔枝》,一路有哪些... 近日, 古装剧《长安的荔枝》热播。 大唐年间, 长安小吏李善德被人设计, 接下了一件“不可能完成”...
让更多基层调解员掌握“茶文化六... “宣讲接地气,直抵人心。”“宣讲内容既有高度,也有温度。”……7月4日,潮州市推广应用“茶文化六步调...
重庆8岁女孩被邻居带到长江游泳... 极目新闻记者 肖名远 7月1日,回重庆丰都县外婆家过暑假的8岁女孩萌萌(化名),在长江中不幸溺亡。4...
协鑫能科将于7月21日召开股东... 金融界7月4日消息,协鑫能科发布公告,将于2025年7月21日召开第3次临时股东大会,网络投票同日进...
合肥39.1℃热到全省第一!晴... 据@安徽气象 14时更新 安徽主要城市气温实况 合肥气温达到39.1℃ 据安徽省气象台预报,7月4...