当前位置: 首页 > news >正文

利用C语言模拟实现堆的基本操作和调堆算法

利用C语言模拟实现堆的基本操作和调堆算法


文章目录

  • 利用C语言模拟实现堆的基本操作和调堆算法
    • 前言
    • 一、堆的基本原理
      • 大根堆和小根堆的比较
    • 二、实现堆的基本操作
      • 1)结构定义
      • 2)初始化堆(HeapInit)
      • 3)销毁堆(HeapDestroy)
      • 4)堆的调整算法
        • (1)向上调堆算法
        • (2)向下调堆算法
      • 5)堆的插入操作(HeapPush)
      • 6)堆的删除操作(HeapPop)
      • 7)获取堆顶元素(HeapTop)
      • 8)获取堆的大小(HeapSize)
      • 9)判断堆是否为空(HeapEmpty)
      • 10)打印堆(HeapPrint)
    • 三、测试堆的功能
    • 总结

前言

​ 堆是一种重要而高效的数据结构,广泛应用于各种算法和数据处理场景。本篇博客将介绍如何使用C语言模拟实现堆的基本操作,包括初始化、插入、删除等,并通过回调函数和函数指针的灵活运用,实现大根堆和小根堆的不同调堆算法。


一、堆的基本原理

堆是一种特殊的树形数据结构,具有以下基本特点:

  • 完全二叉树的结构,即除了最底层,其他层都是满的。
  • 堆中的每个节点的值都必须大于等于或小于等于其子节点的值,根据此条件分为大根堆和小根堆。

堆常被用来实现优先队列等数据结构,其中最值的快速访问是堆的主要优势

大根堆和小根堆的比较

​ 大根堆和小根堆的不同之处在于调堆算法中的比较条件。在大根堆中,父节点的值必须大于子节点的值;而在小根堆中,父节点的值必须小于子节点的值。通过函数指针,我们可以根据用户的选择动态切换调堆算法,使代码更加灵活。

二、实现堆的基本操作

声明: 此处采用动态数组模拟实现堆(完全二叉树)

1)结构定义

定义了堆的结构,包括元素数组、大小、容量和标识是大根堆还是小根堆的字符。

typedef int HPDataType;typedef struct Heap {HPDataType* a;size_t size;size_t capacity;char RootBigOrSmall;
} HP;

2)初始化堆(HeapInit)

通过 HeapInit 函数初始化堆结构,用户可以选择大根堆(‘B’或’b’)或小根堆(‘S’或’s’)。

void HeapInit(HP* php)
{assert(php);printf("请挑选大根堆(big -> B)或小根堆(small -> S): 【输入首字母大小写】");char choose = ' ';choose = getchar();if (choose == 'B' || choose == 'S' || choose == 'b' || choose == 's') { php->RootBigOrSmall = choose; }else { printf("输入有误!"); return; }php->a = NULL;php->capacity = php->size = 0;
}

3)销毁堆(HeapDestroy)

释放堆内存和相关资源的 HeapDestroy 函数。

void HeapDestroy(HP* php)
{assert(php);free(php->a);php->a = NULL;php->capacity = php->size = 0;
}

4)堆的调整算法

(1)向上调堆算法
void adjustUpHeap(HPDataType* a, size_t child, bool (*cmp)(HPDataType _parent, HPDataType _child))
{size_t parent = (child - 1) / 2;if (child == 0) { parent = 0; }while (child > 0){if (cmp(a[parent], a[child])){HPDataType tmp = a[parent];a[parent] = a[child];a[child] = tmp;}child = parent;parent = (parent - 1) / 2;}
}
(2)向下调堆算法
void adjustDownHeap(HPDataType* a, HPDataType size, HPDataType parent,bool (*cmp)(HPDataType _parent, HPDataType _child))
{HPDataType child = parent * 2 + 1;while (child < size){if (child + 1 < size && cmp(a[child], a[child + 1])){child++;}if (cmp(a[parent], a[child])){HPDataType tmp = a[parent];a[parent] = a[child];a[child] = tmp;parent = child;child = child * 2 + 1;}else { break; }}
}

这里采用函数指针作为两种调堆算法的参数是因为通过此方法可实现运行后指定大根堆或小根堆从而影响相关控制堆的操作,比如 HeapPushHeapPop等操作。

5)堆的插入操作(HeapPush)

通过 HeapPush 函数插入元素,并通过向上调堆算法保持堆的性质。

void HeapPush(HP* php, HPDataType x)
{assert(php);// 检查扩容if (php->capacity == php->size){size_t new_capacity = (php->capacity == 0 ? 4 : php->capacity * 2);HPDataType* tmp = (HPDataType*)realloc(php->a, new_capacity * sizeof(HPDataType));if (!tmp) { perror("realloc of HeapPush"); return; }php->a = tmp;php->capacity = new_capacity;}php->a[php->size++] = x;// 调堆bool (*cmp)(HPDataType _parent, HPDataType _child) = NULL;if (php->RootBigOrSmall == 'B' || php->RootBigOrSmall == 'b'){cmp = bigRootHeap_cmp;}else{cmp = smallRootHeap_cmp;}adjustUpHeap(php->a, php->size - 1, cmp);
}

注意: 这里使用动态数组存储堆的节点,所以需要考虑空间扩容问题,当容量不足时利用 realloc() 函数从堆区申请额外空间。

6)堆的删除操作(HeapPop)

通过 HeapPop 函数删除堆顶元素,并通过调堆算法保持堆的性质。

void HeapPop(HP* php)
{assert(php);assert(php->a && php->size > 0);bool (*cmp)(HPDataType _parent, HPDataType _child) = NULL;if (php->RootBigOrSmall == 'B' || php->RootBigOrSmall == 'b'){cmp = bigRootHeap_cmp;}else{cmp = smallRootHeap_cmp;}// 去顶节点HPDataType tmp = php->a[0];php->a[0] = php->a[php->size - 1];php->a[php->size - 1] = tmp;php->size--;// 调堆adjustDownHeap(php->a, php->size, 0, cmp);
}

7)获取堆顶元素(HeapTop)

通过 HeapTop 函数获取堆顶元素。

HPDataType HeapTop(const HP* php)
{assert(php);assert(php->a && php->size > 0);return php->a[0];
}

8)获取堆的大小(HeapSize)

通过 HeapSize 函数获取堆的大小。

size_t HeapSize(const HP* php)
{assert(php);return php->size;
}

9)判断堆是否为空(HeapEmpty)

通过 HeapEmpty 函数判断堆是否为空。

bool HeapEmpty(const HP* php)
{assert(php);return php->size == 0;
}

10)打印堆(HeapPrint)

通过 HeapPrint 函数输出堆的内容。(测试时避免代码冗杂)

void HeapPrint(const HP* php)
{assert(php);for (int i = 0; i < php->size; i++){std::cout << php->a[i] << '\t';}std::cout << "\n";
}

三、测试堆的功能

测试代码:

int main()
{HP hp;HeapInit(&hp);HeapPush(&hp, 15);HeapPush(&hp, 18);HeapPush(&hp, 19);HeapPush(&hp, 25);HeapPush(&hp, 28);HeapPush(&hp, 34);HeapPush(&hp, 65);HeapPush(&hp, 49);HeapPush(&hp, 27);HeapPush(&hp, 37);HeapPrint(&hp);HeapPush(&hp, 30);HeapPrint(&hp);HeapPop(&hp);HeapPrint(&hp);HeapDestroy(&hp);return 0;
}

通过 HeapPrint可以将上面代码分为三部分,第一次 HeapPrint时,对应数组内元素为:

在这里插入图片描述

树状图:

在这里插入图片描述

第二次HeapPrint时:

经历了HeapPush功能,对应数组内元素为:

在这里插入图片描述

树状图:

在这里插入图片描述

第三次HeapPrint时:

经历HeapPop功能:(向下调整算法)

在这里插入图片描述

所得对应数组内元素为:

在这里插入图片描述

运行结果:

在这里插入图片描述

无内存泄漏,HeapDestroy符合设计需求。


总结

​ 本文详细介绍了使用C语言模拟实现堆的基本操作和调堆算法。通过回调函数和函数指针,实现了大根堆和小根堆的灵活切换。堆是一种强大的数据结构,能够在很多应用中提供高效的解决方案。在实际编程中,理解和掌握堆的实现原理对于优化算法和提高代码效率至关重要。

在这里插入图片描述

相关文章:

利用C语言模拟实现堆的基本操作和调堆算法

利用C语言模拟实现堆的基本操作和调堆算法 文章目录 利用C语言模拟实现堆的基本操作和调堆算法前言一、堆的基本原理大根堆和小根堆的比较 二、实现堆的基本操作1&#xff09;结构定义2&#xff09;初始化堆&#xff08;HeapInit&#xff09;3&#xff09;销毁堆&#xff08;He…...

react hooks之useRef和useImperativeHandle

为什么这两个一起写&#xff0c;是因为这两个关联性很大&#xff0c;逐一介绍。 一&#xff1a;useRef 1、作用&#xff1a;用于在函数组件中创建一个持久化的引用变量。这个引用变量可以在组件的多次渲染之间保持不变&#xff0c;并且可以访问和修改 DOM 元素或其他组件实例…...

scala方法与函数

定义方法定义函数方法和函数的区别scala的方法函数操作 1.9 方法与函数 1.9.1 定义方法 定义方法的基本格式是&#xff1a; def 方法名称&#xff08;参数列表&#xff09;&#xff1a;返回值类型 方法体 def add(x: Int, y: Int): Int x y println(add(1, 2)) // 3 //也…...

前端框架(Front-end Framework)和库(Library)的区别

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…...

mysql原理--B+树索引的使用

1.索引的代价 在介绍如何更好的使用索引之前先要了解一下使用这玩意儿的代价&#xff0c;它在空间和时间上都会拖后腿&#xff1a; (1). 空间上的代价 这个是显而易见的&#xff0c;每建立一个索引都要为它建立一棵 B 树&#xff0c;每一棵 B 树的每一个节点都是一个数据页&…...

Android : Room 数据库的基本用法 —简单应用_三_版本

在实体类中添加了新字段&#xff1a; Entity(tableName "people") public class People {//新添加的字段private String email;public String getEmail() {return email;}public void setEmail(String email) {this.email email;}} 再次编译启动时会报错&#xf…...

微服务网关组件Gateway实战

1. 需求背景 在微服务架构中&#xff0c;通常一个系统会被拆分为多个微服务&#xff0c;面对这么多微服务客户端应该如何去调用呢&#xff1f;如果根据每个微服务的地址发起调用&#xff0c;存在如下问题&#xff1a; 客户端多次请求不同的微服务&#xff0c;会增加客户端代码…...

目标检测YOLO系列从入门到精通技术详解100篇-【目标检测】三维重建(补充篇)

目录 前言 算法原理 三维重建意义 三维重建定义 常见的三维重建表达方式...

关于uniapp X 的最新消息

uni-app x 是什么&#xff1f; uni-app x&#xff0c;是下一代 uni-app&#xff0c;是一个跨平台应用开发引擎。 uni-app x 没有使用js和webview&#xff0c;它基于 uts 语言。在App端&#xff0c;uts在iOS编译为swift、在Android编译为kotlin&#xff0c;完全达到了原生应用的…...

spark从表中采样(随机选取)一定数量的行

在Spark SQL中&#xff0c;你可以使用TABLESAMPLE来按行数对表进行采样。以下是使用TABLESAMPLE的示例&#xff1a; SELECT * FROM table_name TABLESAMPLE (1000 ROWS);在这个示例中&#xff0c;table_name是你要查询的表名。TABLESAMPLE子句后面的(1000 ROWS)表示采样的行数…...

java定位系统源码,UWB技术的无线定位系统源码

UWB技术是一种传输速率高&#xff0c;发射功率较低&#xff0c;穿透能力较强并且是基于极窄脉冲的无线技术。UWB最优的应用环境是室内或者相对密闭的空间&#xff0c;有着厘米级的定位精度&#xff0c;不仅可以非常精准地进行位置跟踪&#xff0c;还可以快速地进行数据传输。 智…...

阿里云sls日志服务如何查某个具体字段的平均数

1&#xff1a; 需求&#xff1a; 查询线上某个接口&#xff08;如&#xff1a;list_new&#xff09;的成功率和时延 查接口时延的写法在网上找了一堆&#xff0c;都是语法错误&#xff0c;最后在阿里云官方api找到了正确的 2&#xff1a;贴一下阿里云官方文档&#xff1a; 聚…...

Java八股文面试全套真题【含答案】- Maven篇

以下是一些关于Maven的经典面试题以及它们的答案&#xff1a; 什么是Maven&#xff1f; Maven是一个项目管理工具&#xff0c;用于构建、发布和管理Java项目。它提供了一种标准化的项目结构、依赖管理和构建过程。Maven的核心概念是什么&#xff1f; Maven的核心概念包括POM文…...

从零构建属于自己的GPT系列6:模型本地化部署2(文本生成函数解读、模型本地化部署、文本生成文本网页展示、代码逐行解读)

&#x1f6a9;&#x1f6a9;&#x1f6a9;Hugging Face 实战系列 总目录 有任何问题欢迎在下面留言 本篇文章的代码运行界面均在PyCharm中进行 本篇文章配套的代码资源已经上传 从零构建属于自己的GPT系列1&#xff1a;数据预处理 从零构建属于自己的GPT系列2&#xff1a;模型训…...

不同品牌的手机如何投屏到苹果MacBook?例如小米、华为怎样投屏比较好?

习惯使用apple全家桶的人当然知道苹果手机或iPad可以直接用airplay投屏到MacBook。 但工作和生活的多个场合里&#xff0c;并不是所有人都喜欢用同一品牌的设备&#xff0c;如果同事或同学其他品牌的手机需要投屏到MacBook&#xff0c;有什么方法可以快捷实现&#xff1f; 首先…...

路由和网络周期

### 路由&#xff08;Routing&#xff09;&#xff1a; 1. **路由的概念&#xff1a;** 路由是用于确定用户在网站或应用程序中所处位置的机制。它可以将不同的 URL 映射到对应的页面或视图组件&#xff0c;使得用户可以通过不同的 URL 访问不同的内容。 2. **路由器&#xf…...

【算法与数据结构】332、LeetCode重新安排行程

文章目录 一、题目二、解法三、完整代码 所有的LeetCode题解索引&#xff0c;可以看这篇文章——【算法和数据结构】LeetCode题解。 一、题目 二、解法 思路分析&#xff1a;本题比较属于困难题目&#xff0c;难点在于完成机票、出发机场和到达机场之间的映射关系&#xff0c;再…...

阶段五:深度学习和人工智能(掌握使用TensorFlow或PyTorch进行深度学习)

掌握使用TensorFlow或PyTorch进行深度学习需要具备一定的编程基础和数学基础&#xff0c;包括编程语言、数据结构、算法、线性代数、概率论和统计学等方面的知识。以下是掌握使用TensorFlow或PyTorch进行深度学习的一些基本要求&#xff1a; 了解深度学习的基本概念和原理&…...

DevEco Studio IDE 创建项目时候配置环境

DevEco Studio IDE 创建项目时候配置环境 一、安装环境 操作系统: Windows 10 专业版 IDE:DevEco Studio 3.1 SDK:HarmonyOS 3.1 二、在配置向导的时候意外关闭配置界面该如何二次配置IDE环境。 打开IDE的界面是这样的。 点击Create Project进行环境配置。 点击OK后出现如…...

HTML面试题---专题二

文章目录 一、前言二、解释input标签中占位符属性的用途三、如何在 HTML 中设置复选框或单选按钮的默认选中状态&#xff1f;四、表单输入字段中必填属性的用途是什么&#xff1f;五、如何使用 HTML 创建表格&#xff1f;六、解释a标签中目标属性的用途七、如何创建一个点击后会…...

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…...

设计模式和设计原则回顾

设计模式和设计原则回顾 23种设计模式是设计原则的完美体现,设计原则设计原则是设计模式的理论基石, 设计模式 在经典的设计模式分类中(如《设计模式:可复用面向对象软件的基础》一书中),总共有23种设计模式,分为三大类: 一、创建型模式(5种) 1. 单例模式(Sing…...

【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)

🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...

12.找到字符串中所有字母异位词

&#x1f9e0; 题目解析 题目描述&#xff1a; 给定两个字符串 s 和 p&#xff0c;找出 s 中所有 p 的字母异位词的起始索引。 返回的答案以数组形式表示。 字母异位词定义&#xff1a; 若两个字符串包含的字符种类和出现次数完全相同&#xff0c;顺序无所谓&#xff0c;则互为…...

涂鸦T5AI手搓语音、emoji、otto机器人从入门到实战

“&#x1f916;手搓TuyaAI语音指令 &#x1f60d;秒变表情包大师&#xff0c;让萌系Otto机器人&#x1f525;玩出智能新花样&#xff01;开整&#xff01;” &#x1f916; Otto机器人 → 直接点明主体 手搓TuyaAI语音 → 强调 自主编程/自定义 语音控制&#xff08;TuyaAI…...

《基于Apache Flink的流处理》笔记

思维导图 1-3 章 4-7章 8-11 章 参考资料 源码&#xff1a; https://github.com/streaming-with-flink 博客 https://flink.apache.org/bloghttps://www.ververica.com/blog 聚会及会议 https://flink-forward.orghttps://www.meetup.com/topics/apache-flink https://n…...

【Oracle】分区表

个人主页&#xff1a;Guiat 归属专栏&#xff1a;Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...

智能分布式爬虫的数据处理流水线优化:基于深度强化学习的数据质量控制

在数字化浪潮席卷全球的今天&#xff0c;数据已成为企业和研究机构的核心资产。智能分布式爬虫作为高效的数据采集工具&#xff0c;在大规模数据获取中发挥着关键作用。然而&#xff0c;传统的数据处理流水线在面对复杂多变的网络环境和海量异构数据时&#xff0c;常出现数据质…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

保姆级教程:在无网络无显卡的Windows电脑的vscode本地部署deepseek

文章目录 1 前言2 部署流程2.1 准备工作2.2 Ollama2.2.1 使用有网络的电脑下载Ollama2.2.2 安装Ollama&#xff08;有网络的电脑&#xff09;2.2.3 安装Ollama&#xff08;无网络的电脑&#xff09;2.2.4 安装验证2.2.5 修改大模型安装位置2.2.6 下载Deepseek模型 2.3 将deepse…...