「这是我参与11月更文挑战的第17天,活动详情查看:2021最后一次更文挑战」
💦 堆的实现
1、堆向下调整算法
1 | scss复制代码现在我们给出一个数组,逻辑上看做一颗完全二叉树。我们通过从根节点开始的向下调整算法可以把它调整成一个小堆。 |
❗ 建堆 ❕
有一个随机值的数组,把它理解成完全二叉树,并模拟成堆 (大堆/小堆)
——————————————————-Cut———————————————————
1 | c复制代码int array[] = {27, 15, 19, 18, 28, 34, 65, 49, 25, 37} |
❓ 观察上面这组数据 ❔
根下面的左右子树都是小根堆,其实堆向下调整算法就是针对这种特殊数据结构
——————————————————-Cut———————————————————
❓ 针对于这种类型的数据应该怎么调堆 ❔
思路:从根开始与左右孩子比较,如果孩子比父亲小,则两两交换位置,再继续往下调,直到左右孩子都比父亲大或者调到叶子具体见下图:
——————————————————-Cut———————————————————
❓ 如果不满足左右子树是堆,怎么调整 ❔
1 | c复制代码int array[] = {27, 37, 28, 18, 19, 34, 65, 25, 49, 15} |
根的左右子树 37、28 都不满足:这里的想法就是先让左右子树先满足;而对于左右子树 37、28 来说又需要让 37 先满足;这样依此类推直至满足堆的条件。那干脆就从倒数的第一棵树,也就是倒数的第一个非叶子节点开始调整
2、堆的创建
❗ 这里从倒数的第一个非叶子节点开始调整 ❕
1 | c复制代码#include<stdio.h> |
💨 输出结果:
小堆
大堆
3、堆的时间复杂度
❓ 证明建堆的时间复杂度是O(N) ❔
1 | scss复制代码因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明 |
建堆的调用次数用 T(N) 表示:(从最后一个非叶子节点 <也就是倒数第二层> 开始,最坏的情况下:倒数第二层每个节点最多能向下调 1 次;倒数第三层每个节点最多能向下调 2 次;倒数第四层每个节点最多能向下调 3 次;)
每层节点个数 ×\times× 最坏情况向下调整次数:
T(N) = 2^h-2^ ×\times× 1 + 2^h-3^ ×\times× 2 + … … + 2^0^ ×\times× (h-1)
这里我们从上至下开始
T(N) = 2^0^ ×\times× (h - 1) + 2^1^ ×\times× (h - 2) + 2^2^ ×\times× (h - 3) + 2^3^ ×\times× (h - 4) + … … + 2^h-3^ ×\times× 2 + 2^h-2^ ×\times× 1
❗ 错位相减法 ❕
等号左右两边乘个 2 得到一个新公式,再用新公式减去旧的公式,具体见下图
4、堆的插入
先插入一个10到数组的尾上,再进行向上调整算法,直到满足堆。
5、堆的删除
删除堆是删除堆顶的数据,将堆顶的数据和最后一个数据交换换,然后删除数组最后一个数据,再进行向下调整算法。
6、堆的代码实现
⚠ 注意 ⚠
▶ 堆的初始化一般是使用数组进行初始化的
▶ 堆的插入数据不分头插、尾插,将数据插入后,原来堆的属性不变
先放在数组的最后一个位置,再向上调整
▶ 堆的删除数据删除的是堆顶的数据,将数据删除后,原来堆的属性不变
为了效率,将第一个和最后一个元素交换,再减容,然后再调整
❗ 这里需要三个文件 ❕
1️⃣ Heap.h,用于函数的声明
1 | c复制代码#pragma once |
2️⃣ Heap.c,用于函数的定义
1 | c复制代码#include"Heap.h" |
3️⃣ Test.c,用于测试函数
1 | c复制代码#include"Heap.h" |
本文转载自: 掘金