C语言数据结构易错知识点(3)(堆)

1.堆的本质:完全二叉树

堆在物理结构上是顺序结构,实现方式类似于顺序表(数组);但在逻辑结构上是树形结构,准确来说堆是一棵完全二叉树。因为堆的实现在代码上和顺序表有很高的相似度,所以在写代码时,我们要仔细理解堆的逻辑结构,理解每步操作对该二叉树的影响,我们也可以画画简图,更加直观地感受堆的相关操作的含义。

9c533143795f41fdb8fe967f067d1630.png

2.向上调整与向下调整使用场景

当数据插入堆或从堆顶移除后,都要对堆进行相关的调整,使其成为一个新堆。调整方式分为向上调整和向下调整,它们有不同应用场景

①向上调整:尾部插入数据时使用。当在尾部加入一个新的数据时,这个数据可能要和父节点交换后才能形成大(小)堆,交换过程中除了新插入的节点可能不满足堆的规则以外,其余节点都不需要调整。

函数参数参考:void AdjustUp(HPDataType* arr, int child);

下面举个例子:

c7e6b00301204162b1474f63f8bc04c7.png

 

对于这个小堆,这里新插入了一个0,需要进行调整,我们这时选择向上调整,即沿着祖先向上调整,其余部分不调整

8be48f0eb9a94de8994a40060dbc6d7d.png

 

②向下调整:当数据从堆顶移除建堆时使用

函数参数参考:void AdjustDown(HPDataType* arr, int size, int parent);

a.从堆顶移除数据时向下调整:先交换首元素和尾元素,并用顺序表的方式让size--,使得最后一个元素被删除,再向下调整直到成堆

96fb274916ae40d3a68920b7684c0e6a.png

b.建堆:建堆一般来说有两种方式,一种是向上调整,每次新插入一个元素后向上调整直到成堆;另一种是向下调整,在加入所有数据后从倒数第二行开始向下调整直到成堆。一般来说,我们采用向下调整,因为对于建堆而言,向下调整的时间复杂度近似为O(N-logN)或O(N),而向上调整的时间复杂度为O(NlogN)下面简单讲解一下

向上调整建堆:共有N个元素,每次向上调整logN次,时间复杂度O(logN)

ad616cf9e09f4ca49f7f64f0c1111d11.png

向下调整建堆:第一眼看上去虽然也是O(NlogN),但多观察就发现调整次数远远小于向上调整

521084a4937d4022b90eb1242dfd975b.png

经过详细计算可知比较准确的时间复杂度是O(N-logN),可以再近似于O(N),但我们不用特别纠结于如何精确计算时间复杂度,而是要像上面两张图那样学会粗略地分析和计算

3.堆排序:如果一来就学习堆排序的话,其实会很困难,但如果学会了堆的相关操作,掌握向上和向下调整之后,堆排序就非常简单了。

我们需要用到的知识点就只有:(子节点-1) / 2 == 父节点,父节点 * 2 + 1 == 左孩子结点,父节点 * 2 + 2 == 右孩子结点,堆删除的思路,向下调整。

堆删除的思路对堆排序来说很重要,关键在于首元素和尾元素的交换。 

堆排序关键思路:当我们想让数组从小到大排序,则建立大堆;从大到小排序,则建立小堆。当我们通过大堆找到最大值后,将其与尾元素交换,然后size--达到伪删除的目的(顺序表的删除也可视为一种伪删除,即数据没有被销毁,只是访问不到),重复建堆并交换,次大的数据在最大的数据之前,以此类推......

堆排序的实现注意事项:我们实现堆排序的时候,不要像实现堆那样开辟一整块空间,再push数据、建堆等操作。我们直接在数组上建堆,因为堆排序的物理结构归根到底还是顺序表,只要熟悉堆的操作,我们直接通过下标进行访问修改即可。

Topk问题:这类问题的关键就是要建立k个元素的堆,从小到大排序,则建立大堆;从大到小排序,则建立小堆,从第k + 1个数开始每次删去堆顶元素,再push一个数至堆顶,再向下调整。满足条件的数沉入堆底,不会被删除。理解了这里,那么Topk问题就迎刃而解了。

4.堆和堆排序实现代码:

Heap.h

#pragma once#include <stdio.h>#include <stdlib.h>#include <assert.h>#include <stdbool.h>typedef int HPDataType;typedef struct Heap
{HPDataType* arr;int size;int capacity;}Heap;void HeapInit(Heap* p);void HeapDesTroy(Heap* p);void HPDataTypeSwap(HPDataType* x1, HPDataType* x2);void AdjustUp(HPDataType* arr, int child);void AdjustDown(HPDataType* arr, int size, int parent);void HeapPush(Heap* p, HPDataType x);void HeapPop(Heap* p);bool HeapEmpty(Heap* p);int HeapSize(Heap* p);HPDataType HeapTop(Heap* p);void HeapSort(HPDataType* arr, int size);

Heap.c

#pragma once#include "Heap.h"void HeapInit(Heap* p)
{assert(p);p->capacity = p->size = 0;p->arr = NULL;
}void HeapDesTroy(Heap* p)
{assert(p);free(p->arr);p->arr = NULL;p->capacity = p->size = 0;
}void HPDataTypeSwap(HPDataType* x1, HPDataType* x2)
{assert(x1 && x2);HPDataType tmp = *x1;*x1 = *x2;*x2 = tmp;
}void AdjustUp(HPDataType* arr, int child)
{assert(arr);int parent = (child - 1) / 2;while (child > 0){if (arr[child] < arr[parent]){HPDataTypeSwap(&arr[child], &arr[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}void AdjustDown(HPDataType* arr, int size, int parent)
{assert(arr);int child = parent * 2 + 1;if (parent * 2 + 2 < size){child = arr[child] < arr[child + 1] ? child : child + 1;}while (child < size){if (arr[child] < arr[parent]){HPDataTypeSwap(&arr[child], &arr[parent]);parent = child;child = parent * 2 + 1;if (parent * 2 + 2 < size){child = arr[child] < arr[child + 1] ? child : child + 1;}}else{break;}}}void HeapPush(Heap* p, HPDataType x)
{assert(p);if (p->capacity == p->size){p->capacity = p->capacity == 0 ? 4 : 2 * p->capacity;HPDataType* tmp = (HPDataType*)realloc(p->arr, sizeof(HPDataType) * p->capacity);assert(tmp);p->arr = tmp;}p->arr[p->size++] = x;AdjustUp(p->arr, p->size - 1);
}void HeapPop(Heap* p)
{assert(p);HPDataTypeSwap(&p->arr[0], &p->arr[p->size - 1]);p->size--;AdjustDown(p->arr, p->size, 0);
}bool HeapEmpty(Heap* p)
{assert(p);return p->size == 0;
}int HeapSize(Heap* p)
{assert(p);return p->size;
}HPDataType HeapTop(Heap* p)
{assert(p);if (p->size == 0){printf("空堆,无数据\n");assert(p->size != 0);}return p->arr[0];
}void HeapSort(HPDataType* arr, int size)
{assert(arr);int parent = (size - 2) / 2;while (parent >= 0){AdjustDown(arr, size, parent);parent--;}int sz = size;while (--size){HPDataTypeSwap(&arr[0], &arr[size]);AdjustDown(arr, size, 0);}for (int i = 0; i < sz; i++){printf("%d ", arr[i]);}}

堆测试代码:


#include "Heap.h"//小堆的相关功能实现int main()
{Heap p;HeapInit(&p);HPDataType arr[] = { 10, 9, 8, 7, 4, 5, 6, 2, 1, 3, 12, 11, 13, 15, 14, 16, 19, 17, 18, 20 };for (int i = 0; i < sizeof(arr) / sizeof(HPDataType); i++){HeapPush(&p, arr[i]);}while (HeapEmpty(&p) != true){printf("%d ", HeapTop(&p));HeapPop(&p);}HeapDesTroy(&p);return 0;
}

5395f9d0f4f2494d8fd52a7566d6cc9f.png

堆排序测试代码:


#include "Heap.h"//从大到小int main()
{HPDataType arr[] = { 10, 9, 8, 7, 4, 5, 6, 2, 1, 3, 12, 11, 13, 15, 14, 16, 19, 17, 18, 20 };HeapSort(arr, sizeof(arr) / sizeof(HPDataType));return 0;
}

d2a8814235ea4f2f91bd6948fb23e5a7.png

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/276978.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

关于用max,min函数超时的情况—算法小Tips

今天在做这道题的时候&#xff0c;有了一点对一些题max函数min函数就会超时的思考&#xff0c;不是每道题都这样&#xff0c;但也可以是个做题小tips&#xff1b; 题目连接&#xff1a;登录—专业IT笔试面试备考平台_牛客网 题目很简单&#xff0c;用个前缀和暴力一下就行&…

【Preprocessing数据预处理】之Scaler

在机器学习中&#xff0c;特征缩放是训练模型前数据预处理阶段的一个关键步骤。不同的缩放器被用来规范化或标准化特征。这里简要概述了您提到的几种缩放器&#xff1a; StandardScaler StandardScaler 通过去除均值并缩放至单位方差来标准化特征。这种缩放器假设特征分布是正…

C语言从入门到熟悉------第四阶段

指针 地址和指针的概念 要明白什么是指针&#xff0c;必须先要弄清楚数据在内存中是如何存储的&#xff0c;又是如何被读取的。如果在程序中定义了一个变量&#xff0c;在对程序进行编译时&#xff0c;系统就会为这个变量分配内存单元。编译系统根据程序中定义的变量类型分配…

深度学习 精选笔记(11)深度学习计算相关:GPU、参数、读写、块

学习参考&#xff1a; 动手学深度学习2.0Deep-Learning-with-TensorFlow-bookpytorchlightning ①如有冒犯、请联系侵删。 ②已写完的笔记文章会不定时一直修订修改(删、改、增)&#xff0c;以达到集多方教程的精华于一文的目的。 ③非常推荐上面&#xff08;学习参考&#x…

C++ 入门篇

目录 1、了解C 2、C关键字 2、命名空间 2.1 命名空间的定义 2.2 命名空间的使用 3. C输入与输出 4.缺省参数 4.1 缺省参数的概念 4.2 缺省参数的分类 5. 函数重载 5.1 函数重载的概念 5.2 C中支持函数重载的原理--名字修饰 6. 引用 6.1 引用概念 6.2 引用…

HTML案例-2.标签综合练习

目录 效果 知识点 1.图像标签 2.链接标签 3.锚点定位 4.base标签 源码 页面1 页面2 效果 知识点 1.图像标签 <img src="图像URL" /> 单标签 属性 属性值 描述 src URL 图像的路径 alt 文本

Linux使用Docker部署Registry结合内网穿透实现公网远程拉取推送镜像

文章目录 1. 部署Docker Registry2. 本地测试推送镜像3. Linux 安装cpolar4. 配置Docker Registry公网访问地址5. 公网远程推送Docker Registry6. 固定Docker Registry公网地址 Docker Registry 本地镜像仓库,简单几步结合cpolar内网穿透工具实现远程pull or push (拉取和推送)…

0G联合创始人MICHAEL HEINRICH确认出席Hack.Summit() 2024区块链开发者大会

随着区块链技术的不断发展和应用&#xff0c;全球开发者瞩目的Hack.Summit() 2024区块链开发者大会即将于2024年4月9日至10日在香港数码港盛大举行。此次大会由Hack VC主办&#xff0c;并得到AltLayer和Berachain的协办&#xff0c;同时汇聚了Solana、The Graph、Blockchain Ac…

路由和流量控制

项目拓扑与项目需求 项目需求:某政务网络拥有两个园区&#xff0c;园区A和园区B之间通过物理专线相连。IP地址如图所示。现在需要实现以下需求&#xff1a; 要求A园区无法访问B园区的vlan 30 网络&#xff0c;要求使用路由过滤的方式实现。 配置步骤 设备IP地址的规划 设备名…

从0开始回顾MySQL---事务四大特性

事务概述 事务是一个最小的工作单元。在数据库当中&#xff0c;事务表示一件完整的事儿。一个业务的完成可能需要多条DML语句共同配合才能完成&#xff0c;例如转账业务&#xff0c;需要执行两条DML语句&#xff0c;先更新张三账户的余额&#xff0c;再更新李四账户的余额&…

螺旋阵思维与代码

1.思维 56789419202110318252211217242312116151413观察上面的螺旋阵,你就会发现数字从小到大,按照贝壳的螺旋形依次排列. 走到头就要换一个方向. 看到螺旋数组可以让人想象到贪吃蛇,拿出一个字符串设置为方向,碰到头方向改变,这样循环模拟,直到格子里的数>行和列数(n) .…

c++ 常用函数 集锦 整理中

c 常用函数集锦 目录 c 常用函数集锦 1、string和wstring之间转换 2、经纬度转 xyz 值 互转 3 、获取 根目录下的文件地址 1、string和wstring之间转换 std::string convertWStringToString(std::wstring wstr) {std::string str;if (!wstr.empty()){std::wstring_convert<…

51-31 VastGaussian,3D高斯大型场景重建

2024 年 2 月&#xff0c;清华大学、华为和中科院联合发布的 VastGaussian 模型&#xff0c;实现了基于 3D Gaussian Splatting 进行大型场景高保真重建和实时渲染。 Abstract 现有基于NeRF大型场景重建方法&#xff0c;往往在视觉质量和渲染速度方面存在局限性。虽然最近 3D…

pycharm @NotNull parameter ‘module‘ of ...

下载了最新pycharm &#xff0c;无法启动运行 pycharm或者idea中Run/Debug Python项目报错 Argument for NotNull parameter ‘module‘ of … 解决方案 删除项目根目录的 idea 文件夹 随后重启&#xff0c;重新配置即可

图论(蓝桥杯 C++ 题目 代码 注解)

目录 迪杰斯特拉模板&#xff08;用来求一个点出发到其它点的最短距离&#xff09;&#xff1a; 克鲁斯卡尔模板&#xff08;用来求最小生成树&#xff09;&#xff1a; 题目一&#xff08;蓝桥王国&#xff09;&#xff1a; 题目二&#xff08;随机数据下的最短路径&#…

C++实验 面向对象编程

一、实验目的&#xff1a; 掌握类中静态成员的定义方法&#xff0c;初始化方法&#xff0c;使用方法&#xff1b; 掌握类的友元说明方法&#xff0c;理解友元的使用特点 二、实验内容&#xff1a; 1、编写程序&#xff0c;统计某旅馆住宿客人的总数&#xff0c;要求输入客人…

英国伦敦交易所股票清单列表数据API接口

# Restful API https://tsanghi.com/api/fin/stock/XLON/list?token{token}更新时间&#xff1a;收盘后3~4小时。 更新周期&#xff1a;每天。 请求方式&#xff1a;GET。 # 测试&#xff1a;返回不超过10条数据&#xff08;2年历史&#xff09; https://tsanghi.com/api/fin/…

Linux下的多线程编程:原理、工具及应用(2)

&#x1f3ac;慕斯主页&#xff1a;修仙—别有洞天 ♈️今日夜电波&#xff1a;Flower of Life—陽花 0:34━━━━━━️&#x1f49f;──────── 4:46 &#x1f504; ◀️ ⏸ ▶️ ☰ …

C++第五弹---类与对象(二)

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】 类与对象 1、类对象模型 1.1、如何计算类对象的大小 1.2、类对象的存储方式猜测 1.3、结构体内存对齐规则 2、this指针 2.1、this指针的引出 2.2…

springboot275毕业就业信息管理系统的设计与实现

毕业就业信息管理系统设计与实现 摘 要 传统办法管理信息首先需要花费的时间比较多&#xff0c;其次数据出错率比较高&#xff0c;而且对错误的数据进行更改也比较困难&#xff0c;最后&#xff0c;检索数据费事费力。因此&#xff0c;在计算机上安装毕业就业信息管理系统软件…