目录

满二叉树:  

完全二叉树:

堆是一种特殊的完全二叉树:

我们可以以数组的方式存储堆。

父节点和子节点下标关系的推导:

1.使用数学归纳法证明n2 + 1 = n0:

2.使用边和节点的关系证明n2 + 1 = n0:

我们来看看堆有哪些方法:

向下调整算法:

向上调整算法:

堆排序:

向下调整建堆:

向上调整建堆:

topk问题:


满二叉树:  

定义
一棵深度为 kk 的满二叉树,是指所有非叶子节点都有左右子节点,且所有叶子节点都在最底层的二叉树。换句话说,满二叉树的每一层都被完全填满。

完全二叉树:

定义:

一棵深度为 kk 的完全二叉树,除了最后一层外,其他层的节点都被完全填满,且最后一层的节点尽可能靠左排列。完全二叉树允许最后一层不满,但空缺只能出现在右侧。

堆是一种特殊的完全二叉树:

满足以下性质:

  1. 完全二叉树结构:堆的逻辑结构是一棵完全二叉树(所有层除最后一层外都被填满,且最后一层的节点尽可能靠左排列)。

  2. 堆序性质(Heap Property)

    • 最大堆(Max Heap):每个节点的值 ≥ 其子节点的值(根节点是最大值)。

    • 最小堆(Min Heap):每个节点的值 ≤ 其子节点的值(根节点是最小值)。

当我们给完全二叉树的每个节点从上到下从左到右编个序号。

我们可以发现父节点和子节点的序号之间存在一些关系。

parent*2 + 1 = childleft(左子节点)

parent*2 + 2 = childright(右子节点)

(child-1)/2 = parent.(这是C语言的计算)

当我们知道父节点的下标,就能知道子节点的下标,知道子节点的下标也可以知道父节点的下标。

我们可以以数组的方式存储堆。

注意:

1.只有向下取整的计算规则(当x是小数时,取不大于x的最大整数)才能用数组的形式存储完全二叉树。

2.只有完全二叉树适合用数组来存储

父节点和子节点下标关系的推导:

证明这个关系我们用到了一个二叉树的结论:n2 + 1= n0:度为2的节点个数比度为0的节点个数少一个。

而这个结论也是可以证明的

1.使用数学归纳法证明n2 + 1 = n0:

由于第一个节点满足n2+1 = n0;

假设第k个节点也满足n2+1 = n0;

我们要证明第k+1个节点也满足n2 +1 = n0;

第k+1个节点有两种情况:

情况1:它是一个左子节点:那么度为0的父节点就变成了度为1的节点,同时多出一个度为0的子节点。(度为0的节点个数不变)

情况2:它是一个右子节点:那么度为1的父节点就变成了度为2的节点,同时多出一个度为0的子节点(度为0的节点个数和度为2的节点个数同时+1)。

2.使用边和节点的关系证明n2 + 1 = n0:

像下面这样一个二叉树,一共有6条边,n0+n1+n2-1(除了根节点外的每个节点都贡献一条边)

而边的个数同时也等于n2*2+n1(度为2的节点个数*2 + 度为1的节点个数)

列等式:n0+n1+n2-1 = n2*2+n1

化简得:n0 = n2+1

知道了堆可以用数组来存储,

我们来看看堆有哪些方法:

typedef int HPDataType;
typedef struct Heap
{HPDataType* _a;int _size;int _capacity;
}Heap;void HeapInit(Heap* php);
// 堆的销毁
void HeapDestory(Heap* hp);
// 堆的插入
void HeapPush(Heap* hp, HPDataType x);
// 堆的删除
void HeapPop(Heap* hp);
// 取堆顶的数据
HPDataType HeapTop(Heap* hp);
// 堆的数据个数
int HeapSize(Heap* hp);
// 堆的判空
int HeapEmpty(Heap* hp);

初始化和销毁不用说,其中基本的方法有插入、删除和取堆顶数据。以及堆的数据个数和堆的判空。

在插入数据或者删除数据的时候,为了保证数据始终是以堆的形式在存储,我们引出了向下调整算法和向上调整算法:

向下调整算法:

从一个根开始,父节点和左右子节点中较大的(或者较小的)那个比较,如果父节点小(或者大)就交换,否则就退出循环。

void AdjustDown(HPDataType* a, int n, int root)
{int parent = root;int child = parent * 2 + 1;while (child < n){//建大堆//找出左右孩子中比较大的那个if ((child + 1 < n) && (a[child] < a[child + 1])){child++;}if (a[parent] < a[child]){Swap(&a[parent], &a[child]);parent = child;child = parent * 2 + 1;}else {break;}}
}

向上调整算法:

从一个子节点开始,和它的父节点比较,不符合堆的关系就交换,符合时退出循环。

在实际实现向上调整算法的时候循环判断很容易写错:

如果这里写成了parent >= 0就会导致程序死循环:当parent = 0时,child更新后为0,parent再更新还是为0.

void AdjustUp(HPDataType* a, int child)
{int parent = (child - 1) / 2;while (child > 0)//这个判断条件很容易写错{if (a[parent] < a[child]){Swap(&a[parent], &a[child]);child = parent;parent = (child - 1) / 2;}else {break;}}
}

堆排序:

堆排序的思想就是,对一个无序的数组,首先进行建堆(保证堆顶的数据是最大的或者最小的)。把堆顶的数据交换到堆尾,然后向下调整一遍。同时更新堆尾下标。

void HeapSort(int* a, int n)
{//向下调整建堆for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(a, n, i);}//建好堆之后,交换堆顶和堆尾的数据,向下调整。int end = n - 1;//先创建一个变量记录排序到哪个位置了while (end > 0){Swap(&a[0], &a[end]);AdjustDown(a, end, 0);end--;}
}

这里的建堆方式有两种:一种是向上调整建堆,另一种是向下调整建堆。我们可以分析一下这两种方式的时间复杂度。

完全二叉树向下调整建堆和向上调整建堆最好情况下,最后一层只有一个节点,最坏情况下最后一层是满的,由于我们要分析时间复杂度,所以要选择满二叉树来分析。

向下调整建堆:

从下到上,保证调整的时候只有根不是堆的关系。向下调整建堆可以从第一个非叶子节点开始。

向下调整建堆的时间复杂度是O(N)。

向上调整建堆:

从上到下,保证上层是堆的关系。

向上调整建堆的时间复杂度是N*logN

topk问题:

从n个元素中选出最大(最小)的k个元素。

先建堆,选最大元素建小堆(比榜尾大就入榜),选最小元素建大堆(比榜尾小就入榜)。

void CreateNDate()//创建N个数据的方法
{int n = 10000;FILE* fin = fopen("data.txt", "w");if (fin == NULL){perror("fopen fail");exit(1);}srand((unsigned int)time(NULL));for (int i = 0; i < n; i++){fprintf(fin, "%d\n", rand() % 100000 + 1);}fclose(fin);
}
void PrintTopK(int k)
{//入榜条件是比榜尾要大,所以要和榜尾比较int* topk = (int *)malloc(sizeof(int) * k);//打开文件读取数据FILE* fout = fopen("data.txt", "r");if (fout == NULL){perror("fopen fail\n");exit(1);}int num = 0;//入k个数据for (int i = 0; i < k; i++){fscanf(fout, "%d", &num);topk[i] = num;}//向下调整建堆for (int i = (k - 1 - 1) / 2; i >= 0; i--){AdjustDown(topk, k, i);}//循环判断数据是否入榜while (fscanf(fout, "%d", &num) != EOF){if (num > topk[0]){topk[0] = num;AdjustDown(topk, k, 0);}}fclose(fout);for (int i = 0; i < k; i++){printf("%d ", topk[i]);}
}

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

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

相关文章

3. lvgl 9.3 vscode 模拟环境搭建 lv_port_pc_vscode-release-v9.3

文章目录1. 资源下载1. 1 lv_port_pc_vscode1.2 cmake 和 mingw 环境搭建1.3 sdl 下载1.4 下载lvgl_v9.32. 环境搭建2.1 拷贝lvgl 源码到工程2.2 添加SDL2 依赖2.3 执行工程3. 运行示例1. 资源下载 1. 1 lv_port_pc_vscode 那么多模拟器&#xff0c;为什么选择这个&#xff1…

【牛客刷题】小红的爆炸串(二)

一、题目介绍 本题链接为:小红的爆炸串(二) 小红定义一个字符串会爆炸,当且仅当至少有k对相邻的字母不同。 例如,当 k k k=2时,"arc"会爆炸,而"aabb"则不会爆炸。 小红拿到了一个长度为

【实战】如何训练一个客服语音对话场景VAD模型

1. 引言:客服场景下的VAD模型 在客服中心,每天都会产生海量的通话录音。对这些录音进行有效分析,可以用于服务质量监控、客户意图洞察、流程优化等。VAD在其中扮演着“预处理器”和“过滤器”的关键角色: 提升ASR效率与准确性:只将检测到的语音片段送入ASR引擎,可以避免…

在 Dokploy 中为 PostgreSQL 搭建 PgBouncer 数据库连接池(图文)

前言&#xff1a;为什么你需要一个连接池&#xff1f; 如果你正在使用 Node.js (尤其是像 Next.js 这样的框架) 配合 Prisma 操作 PostgreSQL 数据库&#xff0c;你很可能在某个阶段会遇到那个令人头疼的错误&#xff1a;“Error: Too many clients already”。这通常发生在应…

Mac获取终端历史

在 macOS 中&#xff0c;历史记录文件的位置取决于你使用的 shell。以下是针对不同 shell 的历史记录文件的默认位置&#xff1a;对于 Bash 用户&#xff1a; 历史记录文件通常位于 ~/.bash_history。对于 Zsh 用户&#xff08;macOS Catalina及以后版本默认使用的shell&#x…

高频交易服务器篇

在 Binance 进行高频交易&#xff08;HFT&#xff09;时&#xff0c;服务器的低延迟、高稳定性和快速网络是关键。亚马逊云&#xff08;AWS&#xff09; 提供了多种适合高频交易的方案&#xff0c;以下是推荐的配置和优化策略&#xff1a;1. 选择 AWS 区域&#xff08;Region&a…

MVC与MVVM架构模式详解:原理、区别与JavaScript实现

Hi&#xff0c;我是布兰妮甜 &#xff01;在当今复杂的前端开发领域&#xff0c;如何组织代码结构一直是开发者面临的核心挑战。MVC和MVVM作为两种经典的架构模式&#xff0c;为前端应用提供了清晰的责任划分和可维护的代码组织方案。本文将深入探讨这两种模式的原理、实现差异…

从小白到进阶:解锁linux与c语言高级编程知识点嵌入式开发的任督二脉(2)

【硬核揭秘】Linux与C高级编程&#xff1a;从入门到精通&#xff0c;你的全栈之路&#xff01; 第三部分&#xff1a;Shell脚本编程——自动化你的Linux世界&#xff0c;让效率飞起来&#xff01; 嘿&#xff0c;各位C语言的“卷王”们&#xff01; 在Linux的世界里&#xf…

锁和事务的关系

事务的4大特性(ACID) 原子性&#xff08;Atomicity&#xff09;&#xff1a;事务被视为一个单一的、不可分割的工作单元一致性&#xff08;Consistency&#xff09;&#xff1a;事务执行前后&#xff0c;数据库从一个一致状态转变为另一个一致状态&#xff0c;并且强制执行所有…

电动车信用免押小程序免押租赁小程序php方案

电动车信用免押租赁小程序&#xff0c;免押租小程序&#xff0c;信用免押接口申请、对接开发&#xff0c;可源码搭建&#xff0c;可二开或定制。开发语言后端php&#xff0c;前端uniapp。可二开定制 在线选择门店&#xff0c;选择车辆类型&#xff0c;选择租赁方式&#xff08…

机器学习在智能安防中的应用:视频监控与异常行为检测

随着人工智能技术的飞速发展&#xff0c;智能安防领域正经历着一场深刻的变革。智能安防通过整合先进的信息技术&#xff0c;如物联网&#xff08;IoT&#xff09;、大数据和机器学习&#xff0c;能够实现从传统的被动防御到主动预防的转变。机器学习技术在智能安防中的应用尤为…

MySQL中DROP、DELETE与TRUNCATE的深度解析

在MySQL数据库操作中&#xff0c;DROP、DELETE和TRUNCATE是三个常用的数据操作命令&#xff0c;它们都可以用于删除数据&#xff0c;但在功能、执行效率、事务处理以及对表结构的影响等方面存在显著差异。本文将从多个维度对这三个命令进行详细对比和解析&#xff0c;帮助读者更…

一条 SQL 语句的内部执行流程详解(MySQL为例)

当执行如下 SQL&#xff1a; SELECT * FROM users WHERE id 1;在数据库内部&#xff0c;其实会经历多个复杂且有序的阶段。以下是 MySQL&#xff08;InnoDB 引擎&#xff09;中 SQL 查询语句从发送到结果返回的完整执行流程。 客户端连接阶段 客户端&#xff08;如 JDBC、My…

超详细yolo8/11-detect目标检测全流程概述:配置环境、数据标注、训练、验证/预测、onnx部署(c++/python)详解

文章目录 一、配置环境二、数据标注三、模型训练四、验证预测五、onnx部署c 版python版本 一、配置环境 我的都是在Linux系统下&#xff0c;训练部署的&#xff1b;模型训练之前&#xff0c;需要配置好环境&#xff0c;Anaconda、显卡驱动、cuda、cudnn、pytorch等&#xff1b…

阿里云Flink:开启大数据实时处理新时代

走进阿里云 Flink 在大数据处理的广袤领域中&#xff0c;阿里云 Flink 犹如一颗璀璨的明星&#xff0c;占据着举足轻重的地位。随着数据量呈指数级增长&#xff0c;企业对数据处理的实时性、高效性和准确性提出了前所未有的挑战 。传统的数据处理方式逐渐难以满足这些严苛的需…

【Linux】基础开发工具(1)

1. 软件包管理器 1.1 什么是软件包 在Linux下安装软件, ⼀个常用的办法是下载到程序的源代码, 并进行编译, 得到可执行程序. 但是这样太麻烦了, 于是有些人把⼀些常⽤的软件提前编译好, 做成软件包(可以理解成windows上 的安装程序)放在⼀个服务器上, 通过包管理器可以很⽅便…

蓝桥杯51单片机设计

#超声波原理# ①超声波测距原理&#xff1a;声波反射原理 声波分类&#xff1a; 超声波测距原理 超声波频率越高&#xff0c;波长越短&#xff0c;反身性越强&#xff0c;衍射性越弱 ②超声波模块原理 发射原理 跳线帽 接收原理 问题&#xff1a; &#xff11;.超声波发射模块需…

【LeetCode 热题 100】240. 搜索二维矩阵 II——排除法

Problem: 240. 搜索二维矩阵 II 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&#xff1a; 每行的元素从左到右升序排列。 每列的元素从上到下升序排列。 文章目录 整体思路完整代码时空复杂度时间复杂度&#xff1a;O(M N)空间复…

Android Input 系列专题【inputflinger事件的读取与分发】

Android输入系统在native中的核心工作就是&#xff0c;从Linux驱动设备节点中读取事件&#xff0c;然后将这个事件进行分发&#xff0c;这两项工作分别交给了InputReader和InputDispatcher来做。 他们的源码都属于native层inputflinger里面的一部分&#xff0c;如下架构&#…

【大模型LLM】GPU计算效率评估指标与优化方法:吞吐率

GPU计算效率评估指标与优化方法&#xff1a;吞吐率 一、核心效率指标二、大模型吞吐率&#xff08;Large Model Throughput&#xff09;三、关键性能瓶颈分析四、实际测量工具五、优化策略总结 一、核心效率指标 吞吐率&#xff08;Throughput&#xff09; 定义&#xff1a;单位…