堆的相关特点

一.建堆的两种方法

给定一个数组,其中数组里面的元素个数是n个如何能够把这个数组建立成为一个堆,今天探讨两种方法,分别是向上调整法和向下调整法,分别探讨他们的时间复杂度

向上调整法(以小堆为例)

回顾一下向上调整法

关于向上调整法,我们之前的具体思路是:比较父节点和子节点的大小,如果子节点比父节点小的话就交换两个的值

//交换两个数的值
void Swap(int* a, int* b)
{int temp = *a;*a = *b;*b = temp;
}
//向上调整算法
void AdjustUp(int* a, int n)
{int child = n;int parent = (child - 1) / 2;while (child>0){if (a[child] < a[parent]){Swap(&a[child], &a[parent]);child = parent;parent = (child - 1) / 2;}else{break;}}
}

那么如何运用上面的算法嘞

int main()
{int a[] = { 2,1,4,6,8,3,9};for (int i = 1; i < sizeof(a) / sizeof(a[0]); i++){AdjustUp(a, i);}for (int i = 0; i < sizeof(a)/sizeof(a[0]); i++){printf("%d ", a[i]);}return 0;
}

结果如下

通过画图,我们了解到该结果是正确的

时间复杂度

关于堆(设堆的高度为h)

        

第几层节点数每个节点向上调的次数
02^0 0
12^11
22^22
32^33
h-12^(h-1)h-1

总共调的次数为

O(h)=2^1*1+2^2*2+2^3*3+……+2^(h-1)*(h-1)

两边同时乘以一个2

2O(h)=         2^2*1+2^3*2+2^4*3+……+2^h*(h-1)

上面两个式子相减得到

O(h)=-(2^1+2^2+2^3+……+2^(h-1))+2^h*(h-1)

根据等比数列的前n项和公式得到

O(h)=2^h*(h-2)+2

根据节点数和高度得关系:N=2^h-1 得到:h=log2(N+1)

O(N)=(N+1)[log2(N+1)-2]+2

所以向上调整法建堆的时间复杂度是

O(N)=N*log2(N)

向下调整法(以小堆为例)

思路:从倒数第一个非叶子开始(也就是倒数第二层),一直向下调

void AdjustDown(int* a, int n, int parent)
{int child = parent * 2 + 1;while (child < n){// 假设法,选出左右孩子中小的那个孩子if (child + 1 < n && a[child + 1]< a[child]){++child;}if (a[child] < a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}
}
int main()
{int a[] = { 2,1,4,6,8,3,9};int n = sizeof(a) / sizeof(a[0]);for (int i = (n - 1 - 1) / 2; i >= 0; i--){AdjustDown(a, n, i);}for (int i = 0; i < n; i++){printf("%d ", a[i]);}return 0;
}

时间复杂度

层数节点调整次数
12^0h-1
22^1h-2
32^2h-3
42^3h-4
h2^(h-1)0

所以:

O(h)=2^0*(h-1)+2^1*(h-2)+2^2*(h-3)+……+2^(h-2)*1

等式两边同时乘以一个2得到

2*O(h)=            2^1*(h-1)+2^2*(h-2)+……+2^(h-2)*2+2^(h-1)*1

两式相减得到

O(h)=1-h+2^1+2^2+……+2^(h-1)+2^0-2^0

化简得到 O(N)=N-log2(N+1)

所以向下调整法的时间复杂度为O(N)

堆排序(以升序为例)

给定一个数组,叫你如何排序嘞,这里我们运用建立堆的方式?

关于是建立大堆还是小堆

如果建立小堆的话,不便于后续的操作,这里我们建立一个大堆的方式

那么,如何通过一个大堆来实现数组的升序排序嘞?

比如下面的大堆,先交换数组首尾的值,交换之后不把最后一个元素看做堆里面的元素,继续向下调整,然后重复上面的步骤

int main()
{int a[] = { 46,23,40,35,27,29,30,24 };int n = sizeof(a) / sizeof(a[0]);for (int i = (n - 1 - 1) / 2; i >= 0; i--)   //时间复杂度O(N){AdjustDown(a, n, i);}int end = n - 1;while (end >= 0)                             //时间复杂度O(N*logN){Swap(&a[0], &a[end]);AdjustDown(a, end, 0);end--;}for (int i = 0; i < n; i++){printf("%d ", a[i]);}return 0;
}                                                       //总的时间复杂度O(N*logN)

堆的TOPK问题

场景:给定你一定量的数据,叫你找出最大的10个或者最小的10个数据,如果你用排序的方法来,当这个数据很大的时候,比如100亿,时间复杂度会很大

那么如何用堆的方法来选出前TOPK的数据

1.先建立一个有K个数据的小堆

2.后续的数据和堆顶的数据相比较,如果数据比堆顶的数据大的话,就代替堆顶的数据,这样留下来的数据就是最大的10个

void CreateNDate()
{// 造数据int n = 100000;srand(time(0));const char* file = "data.txt";FILE* fin = fopen(file, "w");if (fin == NULL){perror("fopen error");return;}for (int i = 0; i < n; ++i){int x = (rand() + i) % 1000000;fprintf(fin, "%d\n", x);}fclose(fin);
}void topk()
{printf("请输入k:>");int k = 0;scanf("%d", &k);const char* file = "data.txt";FILE* fout = fopen(file, "r");if (fout == NULL){perror("fopen error");return;}int val = 0;int* minheap = (int*)malloc(sizeof(int) * k);if (minheap == NULL){perror("malloc error");return;}for (int i = 0; i < k; i++){fscanf(fout, "%d", &minheap[i]);}// 建k个数据的小堆for (int i = (k - 1 - 1) / 2; i >= 0; i--){AdjustDown(minheap, k, i);}int x = 0;while (fscanf(fout, "%d", &x) != EOF){// 读取剩余数据,比堆顶的值大,就替换他进堆if (x > minheap[0]){minheap[0] = x;AdjustDown(minheap, k, 0);}}for (int i = 0; i < k; i++){printf("%d ", minheap[i]);}fclose(fout);}int main()
{CreateNDate();topk();return 0;
}

运行结果:

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

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

相关文章

Spring系列-04-事件机制,监听器,模块/条件装配

事件机制&监听器 SpringFramework中设计的观察者模式-掌握 SpringFramework 中, 体现观察者模式的特性就是事件驱动和监听器。监听器充当订阅者, 监听特定的事件&#xff1b;事件源充当被观察的主题, 用来发布事件&#xff1b;IOC 容器本身也是事件广播器, 可以理解成观察…

create-vue源码学习之 gradient-string 渐变色打印

效果 在使用 create-vue 脚手架时&#xff0c;想实现如下的打印效果。 探究过程 翻到源码里看到这一行 没错&#xff0c;绿色部分就是告诉我们如何生成的。可以看到引入了 gradient-string 包 于是乎&#xff0c;我来试试 pnpm i gradient-string pnpm i --save-dev …

1.4、存储系统

目录 存储器的层次结构外存&#xff08;辅存&#xff09;内存CPU的寄存器Cache总结举例局部性原理 练习题 高速缓存Cache总结举例总结 练习题 Cache的地址映像方法直接相联映像全相联映像组相联映像练习题 Cache替换算法Cache页面淘汰算法Cache的读写过程练习题 磁盘总结固态硬…

人工智能(AI)在办公场所的广泛应用

人工智能&#xff08;AI&#xff09;在办公场所的广泛应用正逐步改变着我们的工作方式和效率。随着技术的进步&#xff0c;越来越多的公司和组织开始采用各种AI技术来优化工作流程、提升生产力&#xff0c;并提供更好的用户体验。以下是人工智能在办公方面的一些主要作用和影响…

Ecovadis评估的流程是什么

Ecovadis评估流程是一个全面、系统且注重细节的过程&#xff0c;旨在为企业提供关于其可持续性表现的深入洞察。这一评估不仅覆盖了企业在环境、社会和治理方面的多个方面&#xff0c;还强调了持续改进的重要性&#xff0c;确保企业能够不断提升其CSR&#xff08;企业社会责任&…

社交圈子聊天交友系统搭建社交app开发:陌生交友发布动态圈子单聊打招呼群聊app介绍

系统概述 社交圈子部天交友系统是一个集成即时通讯、社区互动、用户管理等功能的在线社交平台。它支持用户创建个人资料&#xff0c;加入兴趣围子&#xff0c;通过文字、图片、语音、视频等多种方式进行交流&#xff0c;满足用户在不同场景下的社交需求 核心功能 -&#xff0c;…

Window系统下MySQL安装教程

1、MySQL各版本介绍 MySQL Community Edition MySQL Community Edition 是MySQL官方发布的免费版本&#xff0c;适用于个人用户和小型团队使用。它包含了基本的数据库功能&#xff0c;如创建表、插入数据、查询数据等。 MySQL Enterprise Edition MySQL Enterprise Edition 是…

【数据结构】AVL树(图文解析 + 代码实现)

目录 1、AVL树的概念 2、AVL树结点的定义 3、AVL树的插入 4、AVL树的旋转 4.1 左单旋 4.2 右单旋 4.3 右左双旋 4.4 左右双旋 5、AVL树的验证 6、AVL树的性能 前面对map/multimap/set/multiset进行了简单的介绍&#xff0c;会大仙&#xff0c;这几个容器有个共同点是…

【AI大模型】程序员AI的未来——Copilot还是Claude3.5 Sonnet?

近期&#xff0c;Anthropic发布了Claude 3.5 的“大杯”模型 —— Claude 3.5 Sonnet&#xff01; 这次发布的 Sonnet 代表意大利的“十四行诗”&#xff0c;结构复杂&#xff0c;在智能水平、功能多样性和处理能力上都有所提升&#xff0c;能够应对更复杂的认知任务&#xff…

解决VS2019+Qt联合开发双击Resource Files弹不出资源编辑器问题

目录 一、右键Resource.qrc文件 二、选择打开方式 三、鼠标选择Qt Resource Editor&#xff0c;并设置为默认值 四、最后点击确定&#xff0c;再次双击qrc文件&#xff0c;成功打开 最近在开发中&#xff0c;遇见一个问题&#xff0c;在VS联合Qt开发时&#xff0c;需要添加…

前后端分离项目部署,vue--nagix发布部署,.net--API发布部署。

目录 Nginx免安装部署文件包准备一、vue前端部署1、修改http.js2、npm run build 编译项目3、解压Nginx免安装,修改nginx.conf二、.net后端发布部署1、编辑appsetting.json,配置跨域请求2、配置WebApi,点击发布3、配置文件发布到那个文件夹4、配置发布相关选项5、点击保存,…

推荐一款基于 SpringBoot2 的后台管理系统脚手架,非常轻量简单(附源码)

前言 在现代软件开发中&#xff0c;后台管理系统是企业数字化转型的关键组成部分。然而&#xff0c;现有软件常常存在一些痛点&#xff0c;如复杂的权限管理、缺乏灵活的工作流配置、监控和日志功能不完善等。此外&#xff0c;许多系统study 成本高&#xff0c;依赖关系复杂&a…

VS2015加断点(红色),修改过后,断点变为白色不能命中

实际这个问题是因为&#xff1a;源文件和原始版本不同。解决方法有二&#xff1a; 一&#xff0c;在断点上右键&#xff0c;选择“位置”》勾选”允许源代码与原始版本不同&#xff1b; 二&#xff0c;点击菜单栏“调试”》“选项和设置”》“常规”》去掉“要求源文件与原始…

MINE:Mutual Information Neural Estimation

Mutual Information Neural Estimation 摘要 文章认为高维连续随机变量之间的互信息可以通过在神经网络上梯度下降优化得到。 文中提出了互信息估计器(Mutual Information Neural Estimator),它在维度和 样本大小上都是可伸缩的&#xff0c;可以通过反向传播训练的&#xff0…

OCC 布尔运算

目录 一、裁剪原理 二、使用详解 1. 差集 (Cut) 2. 联合 (Fuse/Union) 3. 交集 (Common/Intersection) 三、例子 1、两个盒子裁剪 2、任意面裁剪 四、总结 一、裁剪原理 OpenCASCADE (OCC) 中的裁剪(Boolean Cut)原理主要基于布尔运算。布尔运算是计算机图形学中的…

力扣第二十四题——两两交换链表中的节点

内容介绍 给你一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后链表的头节点。你必须在不修改节点内部的值的情况下完成本题&#xff08;即&#xff0c;只能进行节点交换&#xff09;。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4] 输出&#xff…

Python-numpy基础--------2

1.full()创建函数 目录 1.full()创建函数 2.创建单位矩阵 3.linspace创建 4.logspace 创建 5.二维数组的索引和切片&#xff1a; 1.索引直接获取 在NumPy中&#xff0c;full() 函数用于创建一个给定形状、类型的新数组&#xff0c;并用指定的值填充这个数组。这个函数非…

数模·插值和拟合算法

插值 将离散的点连成曲线或者线段的一种方法 题目中有"任意时刻任意的量"时使用插值&#xff0c;因为插值一定经过样本点 插值函数的概念 插值函数与样本离散的点一一重合 插值函数往往有多个区间&#xff0c;多个区间插值函数样态不完全一样&#xff0c;简单来说就…

AWS监控工具,监控性能指标

执行AWS监视是为了跟踪在AWS环境中主动运行的应用程序工作负载和资源&#xff0c;AWS监视器跟踪各种AWS云指标&#xff0c;以帮助提高在其上运行的应用程序的整体性能。 借助阈值突破警报系统&#xff0c;AWS应用程序监控在识别性能瓶颈来源方面起着至关重要的作用&#xff0c…

linux版mysql8配置表名不区分大小写

mysql8的安装步骤可参考&#xff1a; mysql8的安装步骤 如果在安装mysql8&#xff0c;初始化之前&#xff0c;没有在my.cnf配置忽略大小写配置&#xff1a; [mysqld] lower_case_table_names1我们就需要重新初始化mysql 1 备份数据库文件 2 停止mysql服务 systemctl stop …