【数据结构】堆(C语言)

news2024/11/17 12:38:42

今天我们来学习堆,它也是二叉树的一种(我滴神树!)
在这里插入图片描述

目录

  • 堆的介绍:
  • 堆的代码实现:
    • 堆的结构体创建:
    • 堆的初始化:
    • 堆的销毁:
    • 堆的push:
    • 堆的pop:
    • 判空 && 求Top元素 && 求size:
  • 完整源码:

堆的介绍:

如果有一个关键码的集合K = { , , ,…, },把它的所有元素按完全二叉树的顺序存储方式存储 在一个一维数组中,并满足: <= 且
<= ( >= 且 >= ) i = 0,1,
2…,则称为小堆(或大堆)。将根节点最大的堆叫做最大堆或大根堆,根节点最小的堆叫做最小堆或小根堆。

堆的性质:

  • 堆中某个节点的值总是不大于或不小于其父节点的值;
  • 堆总是一棵完全二叉树。

在这里插入图片描述

堆的代码实现:

堆的结构体创建:

typedef int HpDataType;

typedef struct Heap
{
	int size;
	int capacity;
	HpDataType* a;
}Hp;

堆的初始化:

这里我们选择先不给赋值,等push时再给赋值

void HpInit(Hp* php)
{
	assert(php);

	php->a = NULL;
	php->size = 0;
	php->capacity = 0;
}

堆的销毁:

虽然与初始化相似,但是不能混用

void HpDestory(Hp* php)
{
	assert(php);

	free(php->a);
	php->a = NULL;
	php->size = 0;
	php->capacity = 0;
}

堆的push:

我们需要一个向上调整算法:
在这里插入图片描述
这里我们选择创建小堆

因为我们只有push需要创建newnode,故不需要重新封装一个CreatNewnode函数调整算法时需要传的参数是

void HpPush(Hp* php, HpDataType x)
{
	assert(php);

	if (php->capacity == php->size)
	{
		int newcapacity = (php->capacity == 0 ? 4 : php->capacity * 2);
		HpDataType* tmp = (HpDataType*)realloc(php->a, sizeof(HpDataType)* newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		php->a = tmp;
		php->capacity = newcapacity;
	}

	php->a[php->size] = x;
	php->size++;

	AdjustUp(php->a, php->size - 1);
}

向上调整算法:

注意:
我们在进行向上传参时,要传入动态数组的地址和最后一个叶子节点的下标,为什么不是传入结构体的地址原因会在后来讲解

Swap(HpDataType* e1, HpDataType* e2)
{
	HpDataType tmp = *e1;
	*e1 = *e2;
	*e2 = tmp;
}

void AdjustUp(HpDataType* a, int child)
{
	int parent = (child - 1) / 2;
	//假设进入循环时child > 0
    //这里选择child = 0作为结束标志是因为当child = 0时
    //a[child] 与 a[parent]已经交换过一次了,
    //他们两现在同时指向下标位0,不需要在交换了
	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
		}
		else
		{
			break;
		}

		child = (child - 1) / 2;
		parent = (parent - 1) / 2;
	}
}

堆的pop:

注意:
我们在进行pop时,并不是pop最后的叶子节点,这样没有实际意义,我们要pop的是根节点,这样是有实际意义的,比如Top k问题,堆排序

pop主体部分:

void HpPop(Hp* php)
{
	assert(php);

	Swap(&php->a[php->size - 1], &php->a[0]);
	php->size--;

	AdjustDown(php->a, php->size, 0);
}

同理我们也需要一个向下调整算法
在这里插入图片描述
注意:

传参时仍然是传动态数组a的地址,另外还需要size与根节点0的下标,
size用于判断是否超出堆的范围,0作为parent的初始值

向下调整时我们需要找出孩子节点中较大或较小的那个,在这种情况下我们可以使用假设法,假设后在进行判断是否正确,将两段逻辑变成一段逻辑

AdjustDown(HpDataType* a, int size, int parent)
{
	//假设法
	int child = parent * 2 + 1;

	while (child < size)
	{
		if (child + 1 < size && a[child] > a[child + 1])
		{
			child++;
		}

		if (a[parent] > a[child])
		{
			Swap(&a[parent], &a[child]);
		}
		else
		{
			break;
		}
		child = child * 2 + 1;
		parent = parent * 2 + 1;
	}
}

判空 && 求Top元素 && 求size:

bool HpEmpty(Hp* php)
{
	assert(php);

	return php->size == 0;
}

int HpTop(Hp* php)
{
	assert(php);
	//注意为空
	assert(php->size);

	return php->a[0];
}

int HpSize(Hp* php)
{
	assert(php);

	return php->size;
}

完整源码:

heap.c

#define _CRT_SECURE_NO_WARNINGS 1

#include"heap.h"

void HpInit(Hp* php)
{
	assert(php);

	php->a = NULL;
	php->size = 0;
	php->capacity = 0;
}

void HpDestory(Hp* php)
{
	assert(php);

	free(php->a);
	php->a = NULL;
	php->size = 0;
}

Swap(HpDataType* e1, HpDataType* e2)
{
	HpDataType tmp = *e1;
	*e1 = *e2;
	*e2 = tmp;
}

void AdjustUp(HpDataType* a, int child)
{
	int parent = (child - 1) / 2;

	while (child > 0)
	{
		if (a[child] < a[parent])
		{
			Swap(&a[child], &a[parent]);
		}
		else
		{
			break;
		}

		child = (child - 1) / 2;
		parent = (parent - 1) / 2;
	}
}
//小堆
void HpPush(Hp* php, HpDataType x)
{
	assert(php);

	if (php->capacity == php->size)
	{
		int newcapacity = (php->capacity == 0 ? 4 : php->capacity * 2);
		HpDataType* tmp = (HpDataType*)realloc(php->a, sizeof(HpDataType)* newcapacity);
		if (tmp == NULL)
		{
			perror("realloc fail");
			exit(-1);
		}
		php->a = tmp;
		php->capacity = newcapacity;
	}

	php->a[php->size] = x;
	php->size++;

	AdjustUp(php->a, php->size - 1);
}

AdjustDown(HpDataType* a, int size, int parent)
{
	//假设法
	int child = parent * 2 + 1;

	while (child < size)
	{
		if (child + 1 < size && a[child] > a[child + 1])
		{
			child++;
		}

		if (a[parent] > a[child])
		{
			Swap(&a[parent], &a[child]);
		}
		else
		{
			break;
		}
		child = child * 2 + 1;
		parent = parent * 2 + 1;
	}
}

void HpPop(Hp* php)
{
	assert(php);

	Swap(&php->a[php->size - 1], &php->a[0]);
	php->size--;

	AdjustDown(php->a, php->size, 0);
}

bool HpEmpty(Hp* php)
{
	assert(php);

	return php->size == 0;
}

int HpTop(Hp* php)
{
	assert(php);
	assert(php->size);

	return php->a[0];
}

int HpSize(Hp* php)
{
	assert(php);

	return php->size;
}

heap.h

#pragma once

#include<stdio.h>
#include<stdlib.h>
#include<stdbool.h>
#include<assert.h>

typedef int HpDataType;

typedef struct Heap
{
	int size;
	int capacity;
	HpDataType* a;
}Hp;

void HpInit(Hp* php);

void HpDestory(Hp* php);

void HpPush(Hp* php, HpDataType x);

void HpPop(Hp* php);

bool HpEmpty(Hp* php);

int HpSize(Hp* php);

int HpTop(Hp* php);

有疑问可以及时找博主交流

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

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

相关文章

AI创作工具:Claude2注册保姆级教程

最近软件打算多接入几个AI写作平台&#xff0c;包括讯飞星火&#xff0c;百度文心&#xff0c;Claude2&#xff0c;这样就能给用户提供更多的写作选择 经过半天的调研&#xff0c;讯飞星火&#xff0c;百度文心一言&#xff0c;接入都比较简单&#xff0c;毕竟是国内的。 在调…

鸿蒙HarmonyOS 编辑器 下载 安装

好 各位 之前的文章 注册并实名认证华为开发者账号 我们基实名注册了华为的开发者账号 我们可以访问官网 https://developer.harmonyos.com/cn/develop/deveco-studio 在这里 直接就有我们编辑器的下载按钮 我们直接点击立即下载 这里 我们根据自己的系统选择要下载的系统 例…

关于pytorch以及相关包的安装教程

一.查看自己电脑的配置 首先查看自己电脑的cuda的版本&#xff0c;WinR,敲入cmd打开终端 输入nvidia-smi&#xff0c;查看自己电脑的显卡等配置 这里要说明一下关于这个CUDA,它具有向后兼容性&#xff0c;这意味着支持较低版本的 CUDA 的应用程序通常也可以在较高版本的 CUD…

虚拟机VMware客户机隔离灰色如何解决||实现本机复制粘贴到虚拟机

前言&#xff1a;本次镜像为win10&#xff0c;其他操作系统也欢迎尝试 现象&#xff1a;虚拟机设置选项不可编辑&#xff0c;且是否勾选都无法实现复制粘贴 可能存在的问题解决方案 Q1&#xff1a;未安装虚拟机工具&#xff1a;VMware Tools A1&#xff1a;安装工具&#xff…

Python基础教程之循环结构详解,循环结构逻辑解析。

文章目录 前言一、While循环二、While…else…循环三、for循环四、for…else…循环五、循环体结束语句六、嵌套循环关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例③…

C#,《小白学程序》第五课:队列(Queue)其一,排队的技术与算法

日常生活中常见的排队&#xff0c;软件怎么体现呢&#xff1f; 排队的基本原则是&#xff1a;先到先得&#xff0c;先到先吃&#xff0c;先进先出 1 文本格式 /// <summary> /// 《小白学程序》第五课&#xff1a;队列&#xff08;Queue&#xff09; /// 日常生活中常见…

01_原理-事件循环

01_原理-事件循环 文章目录 01_原理-事件循环一、浏览器的进程模型①&#xff1a;何为进程&#xff1f;②&#xff1a;何为线程&#xff1f;③&#xff1a;浏览器有哪些进程和线程&#xff1f; 二、渲染主线程是如何工作的&#xff1f;三、若干解释①&#xff1a;何为异步&…

人力资源管理后台 === 基础环境+登陆

目录 1.人力资源项目介绍 1.1 项目架构和解决方案 1.2 课程安排 1.3 课程具备能力 1.4 课程地址 2. 拉取项目基础代码 3.项目目录和入口文件介绍 4.App.vue根组件解析 5.基础设置settings.js和导航守卫permission.js 6.Vuex的结构 7.使用模板中的Icon图标 8.扩展…

【Web】NewStarCtf Week2 个人复现

目录 ①游戏高手 ②include 0。0 ③ez_sql ④Unserialize&#xff1f; ⑤Upload again! ⑥ R!!C!!E!! ①游戏高手 经典前端js小游戏 检索与分数相关的变量 控制台直接修改分数拿到flag ②include 0。0 禁了base64和rot13 尝试过包含/var/log/apache/access.log,ph…

了解抽象思维的应用与实践

目录 一、快速了解抽象思维 &#xff08;一&#xff09;抽象思维的本质理解 &#xff08;二&#xff09;系统架构中的重要性 &#xff08;三&#xff09;软件开发中抽象的基本过程思考 意识和手段 抽象的方式 抽象层次的权衡 二、业务中的应用实践 &#xff08;一&…

你知道如何使用队列实现栈吗?(C语言)

这时一道非常经典的题型&#xff0c;因为栈和队列的性质是相反的&#xff0c;队列的数据是先入先出&#xff0c;栈的数据是后入先出&#xff0c;那么怎样使用两个队列实现栈呢&#xff1f; 225. 用队列实现栈https://leetcode.cn/problems/implement-stack-using-queues/ 这是…

212. 单词搜索 II

212. 单词搜索 II Java&#xff1a;搜索全部可能 class Solution {StringBuilder sb;List<String> list;Set<String> set;private void dfs(int x, int y, int m, int n, char[][] board){if (x < 0 || x > m || y < 0 || y > n || board[x][y] .) {…

您的计算机已被.locked1勒索病毒感染?恢复您的数据的方法在这里!

尊敬的读者&#xff1a; 勒索病毒如.locked1已经成为网络安全的一大威胁。这类病毒通过加密用户文件&#xff0c;并勒索赎金以解密这些文件&#xff0c;给用户和组织带来了巨大的损害。本文将深入介绍.locked1勒索病毒的特点、恶意目的&#xff0c;以及如何恢复被其加密的数据…

多丽特膳:肥胖与七大营养素的关系、影响及作用

在探讨肥胖与身体的关系时&#xff0c;我们不能忽视七大营养素的重要作用。这些营养素包括碳水化合物、蛋白质、脂肪、维生素、矿物质、膳食纤维和水。它们对肥胖和身体的影响及作用各有不同&#xff0c;一起构成了我们日常饮食的基础&#xff0c;那么让我来给大家说道说道它们…

install pnpm : 无法加载文件的解决办法

问题描述 我在使用pnpm的时候报错 PS D:\emss\pure-admin-backend> pnpm install pnpm : 无法加载文件 C:\Users\RD-16\AppData\Roaming\npm\pnpm.ps1。未对文件 C:\Users\RD-16\AppData\Roaming\npm\pnpm.ps1 进行数字签名。无法在当前系统上运 行该脚本。有关运行脚本和设…

Springboot实现增删改差

一、包结构 二、各层代码 (1)数据User public class User {private Integer id;private String userName;private String note;public User() {super();}public User(Integer i, String userName, String note) {super();this.id i;this.userName userName;this.note note;…

最新AI创作系统ChatGPT网站运营源码、支持GPT-4-Turbo模型,图片对话识图理解,支持DALL-E3文生图

一、AI创作系统 SparkAi是目前国内一款的ChatGPT对接OpenAI软件系统。那么如何搭建部署AI创作ChatGPT&#xff1f;小编这里写一个详细图文教程吧&#xff01;本系统使用NestjsVueTypescript框架技术&#xff0c;持续集成AI能力到本系统。支持OpenAI DALL-E3文生图&#xff0c;…

罗技M590鼠标usb优联连接不上

手里有一个罗技M590鼠标从18年4月一直用到现在&#xff0c;质量很好&#xff0c;除了滚轮有些松别的没毛病。最近一台笔记本电脑办公不太够用&#xff0c;又领了一个台式机&#xff0c;就想到M590支持双模连接&#xff0c;并且支持Flow&#xff0c;就把usb优联接收器从电池仓拿…

深度学习图像风格迁移 计算机竞赛

文章目录 0 前言1 VGG网络2 风格迁移3 内容损失4 风格损失5 主代码实现6 迁移模型实现7 效果展示8 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习图像风格迁移 - opencv python 该项目较为新颖&#xff0c;适合作为竞赛课题…

麒麟linux离线安装dotnet core

1. 下载 dotnet core,以3.1为例 下载地址: 下载 .NET Core 3.1 (Linux、macOS 和 Windows) 查看linux cpu类型,然后根据类型下载 uname -m #结果是: aarch64 2. 放到指定目录,比如:/usr/dotnet 3. 解压dotnet-sdk-3.1.426-linux-arm64.tar.gz cd /usr/dotnet tar –zxvf a…