6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)

news2024/9/25 7:13:53

目录

一.堆(Heap)的基本介绍

二.堆的常用操作(以小根堆为例)

三.实现代码

3.1 堆结构定义

3.2 向下调整算法*

3.3 初始化堆*

3.4 销毁堆

3.4 向上调整算法*

 3.5 插入数据

3.6 删除数据

3.7 返回堆顶数据

四.下篇内容

1.堆排序

2.TopK问题


一.堆(Heap)的基本介绍

        了解堆之前我们要简单了解完全二叉树:        

        在二叉树中,我们使用指针来连接每一个结点,最后构成一颗二叉树。而堆是一种使用数组来表示完全二叉树。其满足以下两条规则。

        1.堆中结点值总是大于或者小于其父结点的值。

        2.堆总是一颗完全二叉树。

由此可以推出有两种堆:大根堆和小根堆。

大根堆:根节点的值最大。

小根堆:根节点的值最小。

在堆(二叉树)中,如果一个结点的下标为i

其父亲的结点的下标为 (i-1)/ 2

其左孩子结点的下标为 (i+1)*2 -1  即  i*2 +1

其右孩子结点的下标为 (i+1)*2      即  i*2 + 2

数组的下标由0开始,读者可根据下图进行理解

二.堆的常用操作(以小根堆为例)

//初始化堆
void HeapInit(Heap* php, DataType* arr, int n);

//数组建堆主要依赖的算法(这个算法要求数组的左右子树都是小堆)
//小堆,使用向下调整算法
void Adjustdown(DataType* arr, int n, int root);


//向上调整算法
void Adjustup(DataType* arr, int n, int root);

//销毁堆
void HeapDestory(Heap* php);

//插入数据
void HeapPush(Heap* php, DataType x);

//删除数据
void HeapPop(Heap* php, DataType x);

//求堆顶(根)数据
DataType HeadTop(Heap* php);

//交换两个数据
void swap(DataType* p1, DataType* p2);

三.实现代码

3.1 堆结构定义

//以小根堆为例
typedef int DataType;
typedef struct Heap
{
	DataType* arr;    //数组
	int capacity;     //容量
	int size;         //元素大小
}Heap;

3.2 向下调整算法*

        小根堆使用该算法的前提是左右子树都为小根堆,大根堆的前提是左右子树都为大根堆

该算法是从根结点依次向下找到比自己小(或者大)的结点,然后进行交换。

最后就能将新插入的根节点放到相应的位置

调整规则:

小根堆:根节点每一次与孩子结点中较小的一个交换

大根堆:根节点每一次与孩子结点中较大的一个交换

如下图

代码如下(以小根堆为例)

//向下调整算法
void AdjustDwon(DataType* arr, int n, int root)
{
	//1.小根堆,找出左右孩子中较小的结点
	int parent = root;
	int child = root * 2 + 1;	//表示左孩子
	while (child < n)
	{
		//找到右孩子,如果右孩子比左孩子小,让child++。注意必须存在右孩子才能这么做
		if (child + 1 < n && arr[child + 1] < arr[child])
		{
			child++;
		}

		//如果该孩子比父亲小,就要交换
		if (arr[child] < arr[parent])
		{
			swap(arr[child], arr[parent]);

			//向下继续调整
			parent = child;
			child = parent * 2 + 1;
		}
		else
		{
			//如果孩子比父亲大,交换结束
			break;
		}
	}
}

3.3 初始化堆*

        初始化堆:将一个随机的数组(数组大小随机,元素大小也随机)转换为堆。

思路:

1.将一个数组拷贝到一个堆结构中

2.利用向下调整算法对整个数组进行调整,由于整个数组不能直接进行向下调整(左右子树不符合堆结构),所以我们使用向下调整算法堆 最后一个结点的父亲结点开始调整,然后依次对这个结点之前的结点开始调整。

3.最后得出完整的堆结构

流程图:

代码

//初始化堆
void HeapInit(Heap* hp, DataType* arr, int n)
{
	//开辟空间,大小为 DataType*n
	hp->arr = (DataType*)malloc(sizeof(DataType) * n);
	assert(hp->arr != nullptr);
	memcpy(hp->arr, arr, sizeof(DataType) * n);
	hp->size = n;
	hp->capacity = n;

	//拷贝好数据后,由于数据是随机的,所以我们使用调整算法建堆
	//我们从最后一个度为2的结点开始向前依次对每一个结点都进行向下调整
	//最后一个结点下标为 n-1 则其父亲结点为(n-1-1)/2
	for (int i = (n - 1 - 1) / 2; i > 0; i--)
	{
		Adjustdown(hp->arr, hp->size, i);
	}
}

3.4 销毁堆

//销毁堆
void HeapDestory(Heap* php)
{
	assert(php);
	free(php->arr);
	php->arr = NULL;
	php->size = 0;
	php->capacity = 0;
}

3.4 向上调整算法*

当我们插入新数据时,这个数据会破坏堆结构(如插入到数组末尾),所以我们需要向上调整

和向下调整算法类似

思路:

        让新增节点依次和自己的父亲比较,然后交换即可

        小根堆:比父亲小,交换。直到比父亲大就结束

        大根堆:比父亲大,交换。直到比父亲小就结束

流程图:

代码

//向上调整算法,以小根堆为例
void AdjustUp(DataType* arr, int n, int child)
{
	int parent = (child - 1) / 2;
	while (child > 0)
	{
		if (arr[child] < arr[parent])
		{
			swap(arr[child], arr[parent]);
			
			//继续向上调整
			child = parent;
			parent = (child - 1) / 2;
		}
		else
		{
			break;
		}
	}
}

 3.5 插入数据

//插入数据
void HeapPush(Heap* hp, DataType x)
{
	assert(hp);
	//1.增容
	if (hp->size == hp->capacity)
	{
		hp->capacity *= 2;
		DataType* tmp = (DataType*)realloc(hp->arr, sizeof(DataType) * hp->capacity);
		assert(tmp != NULL);
		hp->arr = tmp;
	}
	//2.在数组的插入数据
	hp->arr[hp->size] = x;
	hp->size++;

	//对数组进行向上调整,将小的数据向上调整
	Adjustup(hp->arr, hp->size, hp->size - 1);
}

3.6 删除数据

删除堆顶的数据

我们交换第一个数据和最后一个数据,然后删除最后一个数据。再对堆顶进行向下调整

这样就能满足删除后,整个堆还是满足规则的

//删除数据(删掉堆顶的数据)
//类似于堆排序,交换第一个和最后一个数据。保证根节点的左右子树都是小根堆
void HeapPop(Heap* hp)
{
	assert(hp);
	assert(hp->arr);
	swap(hp->arr[0], hp->arr[hp->size - 1]);
	hp->size--;
	Adjustdown(hp->arr, hp->size, 0);
}

3.7 返回堆顶数据

直接返回0下标处的数据即可

//求堆顶(根)数据
DataType HeadTop(Heap* hp)
{
	assert(hp);
	assert(hp->size > 0);
	return hp->arr[0];
}

四.下篇内容

1.堆排序

2.TopK问题

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

案例-KVM+GFS分布式存储系统构建KVM高可用(虚拟化实战)

NFS GlusterFS 基于共享存储 采用GFS做共享存储&#xff1b; 实验环境&#xff1a;101 102 103 104 做gfs集群&#xff1b;201 202做虚拟机&#xff1b; 同步一下会话&#xff1b; 为了方便使用主机名进行通信&#xff0c;修改hosts文件&#xff1b; 为了使用GlusterFS的仓库…

国内独家首发 | OpenCSG开源中文版fineweb edu数据集

01 背景 近年来&#xff0c;人工智能&#xff08;AI&#xff09;技术&#xff0c;特别是自然语言处理&#xff08;NLP&#xff09;的飞速发展深刻影响着各个行业。从智能客服到内容生成&#xff0c;从语音识别到翻译工具&#xff0c;NLP的应用已经无处不在。在这一领域中&…

[线程]JUC中常见的类 及 集合类在多线程下的线程安全问题

文章目录 一. JUC中常见的类1. Callable接口2. ReentrantLock3. Semaphore 信号量4. CountDownLatch 二. 集合类在多线程下的线程安全问题多线程下使用ArrayList多线程下使用哈希表(重要) 下面介绍的内容是面试中常考, 但是实际开发中用不到的知识 一. JUC中常见的类 JUC : ja…

『功能项目』主角身旁召唤/隐藏坐骑【20】

本章项目成果展示 我们打开上一篇19坐骑UI搭建及脚本控制显/隐的项目&#xff0c; 本章要做的事情是在坐骑UI界面点击召唤及隐藏坐骑的功能 首先在外包中拖拽一个坐骑熊的预制体 完全解压缩 重命名为MountBear 在资源文件夹Resources下的/预制体文件夹Prefabs下新建坐骑文件夹…

海外合规|新加坡网络安全认证计划简介(三)-Cyber Trust

一、 认证简介&#xff1a; Cyber Trust标志是针对数字化业务运营更为广泛的组织的网络安全认证。该标志针对的是规模较大或数字化程度较高的组织&#xff0c;因为这些组织可能具有更高的风险水平&#xff0c;需要他们投资专业知识和资源来管理和保护其 IT 基础设施和系统。Cy…

新质生产力人工智能+系列5-智能业务识别研究(含任务、数据、算力资源)

在新质生产力高质量发展的要求下&#xff0c;中国移动在“人工智能”和 “数据要素X”方面不断发力&#xff0c;持续发布高质量电信数据集。围绕网元智能、运维智能、服务智能三大方向建设&#xff0c;涵盖无线信道、基站、云网、核心网、哑资源等多领域&#xff0c;支持感知、…

护工系统|护工陪护系统|护工小程序

在医疗服务行业日新月异的今天&#xff0c;陪护机构正乘着数字化转型的东风&#xff0c;扬帆远航&#xff0c;其中&#xff0c;护工系统的引入无疑为其插上了一对强劲的翅膀&#xff0c;引领着行业向更加高效、精细化的方向迈进。这一系统不仅是对传统陪护模式的深刻重塑&#…

oracle物理存储结构文件详解

文章目录 oracle物理文件结构图① 控制文件&#xff1a;② 数据文件&#xff1a;③ 联机Redo日志文件&#xff1a;④ 参数文件&#xff1a;⑤ 归档文件&#xff1a;⑥ 密码文件&#xff1a; oracle物理文件结构图 Oracle数据库的物理结构由控制文件&#xff08;Control f…

硬件工程师笔试面试知识器件篇——电容

目录 电容 2.1、基础 电容原理图 电容实物图 2.1.1、定义 2.1.2、原理 2.1.3、电容的类型 分类1: 分类2: 2.1.4、电容的应用 2.2、相关问题 2.2.1、电容器的电容值如何测量 2.2.2、不同类型的电容器在实际应用中有那些具体差异 2.2.3、如何选择合适的电容器来满…

OrangePi AIpro 香橙派 昇腾 Ascend C 算子开发 与 调用 - Tiling实现 2

OrangePi AIpro 香橙派 昇腾 Ascend C 算子开发 与 调用 - Tiling实现 2 flyfish 前置知识 1 前置知识 2 Host侧CPU和Device侧NPU的主要区别 不同的硬件资源 CPU是为了执行通用计算任务而设计的&#xff0c;但在处理大量的并行计算&#xff08;如矩阵乘、批数据处理&#…

智能优化算法-北方苍鹰优化算法(NGO)(附源码)

目录 1.内容介绍 2.部分代码 3.实验结果 4.内容获取 1.内容介绍 北方苍鹰优化算法 (Northern Goshawk Optimizer, NGO) 是一种基于群体智能的元启发式优化算法&#xff0c;它模拟了北方苍鹰&#xff08;Northern Goshawk&#xff09;的捕食行为、领地行为以及社交互动&#x…

input系统之InputDispatcher

往期文章&#xff1a; Input系统之IMS的启动流程 input系统之InputReader 1.概述 InputReader和InputDispatcher是Input系统的重要组成部分&#xff0c;InputReader主要负责从设备节点获取原始输入事件&#xff0c;并将封装好的事件交给InputDispatcher&#xff1b;InputDis…

数据库 | 子查询 | sql执行顺序 | mysql是否运行

1.系统&#xff08;客户端&#xff09;访问 MySQL 服务器前&#xff0c;做 的第一件事就是建立 TCP 连接。 Caches & Buffers&#xff1a; 查询缓存组件SQL Interface: SQL接口 接收用户的SQL命 令&#xff0c;并且返回用户需要查询的结果。比如 SELECT … FROM就是调用SQ…

防止goroutine崩溃导致主进程崩溃

在Go语言中&#xff0c;当一个goroutine发生异常时&#xff0c;它会直接退出&#xff0c;并不会影响其他goroutine或者主进程。Go语言的设计哲学是“不要通过共享内存来通信&#xff0c;而应该通过通信来共享内存”。这就意味着&#xff0c;goroutine之间的协作通常是通过chann…

Azure AI Search 中的二进制量化:优化存储和加快搜索速度

随着组织继续利用生成式 AI 的强大功能来构建检索增强生成 (RAG) 应用程序和代理&#xff0c;对高效、高性能和可扩展解决方案的需求从未如此强烈。 今天&#xff0c;我们很高兴推出二进制量化&#xff0c;这项新功能可将向量大小减少高达 96%&#xff0c;同时将搜索延迟减少高…

2024.9.4 作业

自己实现栈和队列的全类型 代码&#xff1a; /*******************************************/ 文件名&#xff1a;sq.h /*******************************************/ #ifndef SQ_H #define SQ_H #include <iostream> #include <stdexcept> using namespace…

文档一键生成组织架构图,这款在线AI工具让你事半功倍!

在呈现公司组织架构或部门层级时&#xff0c;经常会用到组织架构图&#xff0c;组织架构图是一种直观的可视化工具&#xff0c;用于展示一个组织内部的层级结构和各部门之间的关系。 在制作组织架构图时&#xff0c;如果拿到的是清晰的人员关系&#xff0c;绘制起来还比较简单…

LeetCode 热题100-64 搜索二维矩阵

搜索二维矩阵 给你一个满足下述两条属性的 m x n 整数矩阵&#xff1a; 每行中的整数从左到右按非严格递增顺序排列。每行的第一个整数大于前一行的最后一个整数。 给你一个整数 target &#xff0c;如果 target 在矩阵中&#xff0c;返回 true &#xff1b;否则&#xff0c…

访问Swagger:java.lang.NumberFormatException: For input string: ““

你们好&#xff0c;我是金金金。 场景 启动项目&#xff0c;接着访问Swagger 依赖版本如下&#xff1a;1.5.20 查看控制台输出&#xff1a;报错如下 排查 首先看报错&#xff1a;For input string: “”&#xff1a;这个错误表明程序尝试将一个空字符串&#xff08;“”&#x…

JavaWeb JavaScript 9.正则表达式

生命的价值在于你能够镇静而又激动的欣赏这过程的美丽与悲壮 —— 24.8.31 一、正则表达式简介 正则表达式是描述字符模式的对象。正则表达式用简单的API对字符串模式匹配及检索替换&#xff0c;是对字符串执行模式匹配的强大工具。 1.语法 var pattnew RegExp(pattern,modi…