重生之“我打数据结构,真的假的?”--5.堆(无习题)

1.堆的概念与结构

如果有⼀个关键码的集合 ,把它的所有元素按完全⼆叉树的顺序存储⽅ 式存储,在⼀个⼀维数组中,并满⾜: ( 且 ), i = 0、1、2... ,则称为⼩堆(或⼤堆)。将根结点最⼤的堆叫做最⼤堆或⼤根堆根结点最⼩的堆 叫做最⼩堆或⼩根堆

2.堆的性质

• 堆中某个结点的值总是不⼤于或不⼩于其⽗结点的值;

• 堆总是⼀棵完全⼆叉树

3.堆的实现

3.1初始化及基础功能

typedef struct heap
{int* a;int size;int capacity;
}HP;void heapinit(HP* php)
{assert(php);php->a = NULL;php->size = 0;php->capacity = 0;
}                    //初始化void swap(int* p1, int* p2)
{int t = 0;t = *p1;*p1 = *p2;*p2 = t;
}                   //交换函数void heappush(HP* php, int data)
{if (php->size == php->capacity)   //如果内存空间满了{int newcapacity = php->capacity == 0 ? 4 : php->capacity * 2;                          //内存空间和元素数量一样》》》》》1.内存空间为0,令内存大小为4, 2.内存空间满了,扩容至两倍大int* tmp = (int*)realloc(php->a, newcapacity * sizeof(int));                           //开辟内存空间记得加sizeof(sldatatype) php->a = tmp;                                                                          //开辟内存空间赋给a指针php->capacity = newcapacity;                                                           //设置新的容量}php->a[php->size] = data;php->size++;adjustup(php->a, php->size - 1);
}void heappop(HP* php)
{swap(&php->a[0],&php->a[php->size - 1]);php->size--;adjustdown(php->a,php->size-1,0);//首尾互换!!!!!!,可以保证根节点以下的二叉树均不被改变(即排好序),只需由新的根节点从上往下排序交换一轮
}bool heapempty(HP* php)
{return php->size == 0;
}                               //判断是否为空int heaptop(HP* php)
{assert(php);return php->a[0];
}                               //取根节点

3.2 向上调整算法

向上调整算法

• 先将元素插⼊到堆的末尾,即最后⼀个孩⼦之后

• 插⼊之后如果堆的性质遭到破坏,将新插⼊结点顺着其双双亲往上调整到合适位置即可

(要求插入前必须是堆)!!!!!!

void adjustup(int* 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;}}
}

3.3 向下调整算法

向下调整算法

• 将堆顶元素与堆中最后⼀个元素进⾏交换

• 删除堆中最后⼀个元素

• 将堆顶元素向下调整到满⾜堆特性为⽌

!!!!!!向下调整算法有⼀个前提:左右⼦树必须是⼀个堆,才能调整。

 

void adjustdown(int* a,int n, int parent)     //向下调整法,!!!!!!(仅适用于根结点两端都是大堆或小堆)
{int child = 2 * parent + 1;while (child<=n)                   //{if (child + 1<=n && a[child + 1] > a[child])      //   child+1>n可以推出child==n,所以只有左孩子{child++;                          //选出左右孩子中最大的一个‘>’,最小的为'<'}if (a[parent]<=a[child])        //大堆为“<=”,小堆为“>=”{swap(&a[parent], &a[child]);parent = child;child = 2 * parent + 1;     //每次都先找左孩子}else{break;}}
}

 

4.堆排序 

int main()
{int a[] = { 65,100,70,32,50,35 };int i;int n = sizeof(a) / sizeof(a[0]);int flag = n;for (i = 1; i < sizeof(a) / sizeof(a[0]); i++)     //i从1开始,因为只有一个元素时可以视作堆{adjustup(a, i);}                    //升序排序前的第一步,建立大堆,i从1开始,因为i=0时可视作堆,从1开始向上调整//记住,只是建好了堆,堆不代表直接打印出来是有序的!!!!!!!!!还需要调整while (n>0)          //上文所说的调整,因为是大堆,所以root一定是最大的{swap(&a[0],&a[n-1]);//将最大的换到tailn--;                //不再关注最大的tailadjustdown(a,n-1, 0);//排除tail后重新建立大堆,选择从根开始的向下调整最合适(交换后,根的左右两边都是堆,只是根变了),让第二大的变为root,循环}                  for (i = 0; i <= flag - 1; i++)printf("%d ",a[i]);return 0;
}

5.实际问题解决 ——topK问题

TOP-K问题:即求数据结合中前K个最⼤的元素或者最⼩的元素,⼀般情况下数据量都⽐较⼤。 ⽐如:专业前10名、世界500强、富豪榜、游戏中前100的活跃玩家等。 对于Top-K问题,能想到的最简单直接的⽅式就是排序,但是:如果数据量⾮常⼤,排序就不太可取了 (可能数据都不能⼀下⼦全部加载到内存中)。最佳的⽅式就是⽤堆来解决,基本思路如下:

1)⽤数据集合中前K个元素来建堆

前k个最⼤的元素,则建⼩堆

前k个最⼩的元素,则建⼤堆

2)⽤剩余的N-K个元素依次与堆顶元素来⽐较,不满⾜则替换堆顶元素

将剩余N-K个元素依次与堆顶元素⽐完之后,堆中剩余的K个元素就是所求的前K个最⼩或者最⼤的元素

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);
}

 

 

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

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

相关文章

【数组中的 k-diff 数对】python刷题记录

R2-哈希表。 有点easy的感觉 class Solution:def findPairs(self, nums: List[int], k: int) -> int:#查找对的方式是查找xk&#xff0c;不查找x-k是避免查找重复#此外&#xff0c;需要注意k0的问题mp{}for x in nums:if x in mp:mp[x]1else:mp[x]1ret0for x,cnt in mp.ite…

2024年7月25日(Git gitlab以及分支管理 )

分布式版本控制系统 一、Git概述 Git 是一种分布式版本控制系统,用于跟踪和管理代码的变更。它是由Linus Torvalds创建的,最 初被设计用于Linux内核的开发。Git允许开发人员跟踪和管理代码的版本,并且可以在不同的开 发人员之间进行协作。 Github 用的就是Git系统来管理它们的…

C++内存管理和模板/stl初识

前言 c兼容C语言&#xff0c;但它因为有类和对象的概念&#xff0c;C语言原生的那套内存管理函数在特定场景下还是有些捉襟见肘的&#xff0c;为此c在C语言的基础上引入新的内存管理方案&#xff0c;今天我们就来简单的认识一下c的内存管理。除此之外&#xff0c;模板也是c引入…

数据结构与算法——赫夫曼编码

1、基本介绍 &#xff08;1&#xff09;赫夫曼编码也翻译为 哈夫曼编码(Huffman Coding)&#xff0c;又称霍夫曼编码&#xff0c;是一种编码方式。属于一种程序算法。赫夫曼编码是赫夫曼树在电信通讯中经典的应用之一。 &#xff08;2&#xff09;赫夫曼编码被广泛地应用于数据…

C语言程序设计13

程序设计13 问题13_1代码13_1结果13_1 问题13_2代码13_2结果13_2 问题13_3代码13_3结果13_3 问题13_1 函数 f u n fun fun 的功能是&#xff1a;把形参 s s s 所指字符串中下标为奇数的字符右移到下一个奇数位置&#xff0c;最右边被移出字符串的字符绕回放到第一个奇数位置&…

77.WEB渗透测试-信息收集-框架组件识别利用(1)

免责声明&#xff1a;内容仅供学习参考&#xff0c;请合法利用知识&#xff0c;禁止进行违法犯罪活动&#xff01; 内容参考于&#xff1a; 易锦网校会员专享课 上一个内容&#xff1a;76.WEB渗透测试-信息收集- WAF、框架组件识别&#xff08;16&#xff09; java&#xff…

Cannot access org.springframework.context.ConfigurableApplicationContext

Cannot access org.springframework.context.ConfigurableApplicationContext SpringApplication.run曝红 解决方案&#xff1a; File -> Invalidate Cache and Restart 如果对你有用就点个赞&#xff01;

FPGA开发——奇数分频器的设计

一、概论 在我们进行FPGA分频器的学习当中&#xff0c;我们通常会学习怎样完成任意分频器的设计&#xff0c;其中就包括偶数分频最为常见。在实现的分频器的同时我们也会不定时的要求同时设置对应的占空比。今天我们就来看看怎样同时设置奇数分频器和其对应50%的占空比。 二、…

LabVIEW操作系列1

系列文章目录 我的记录&#xff1a; LabVIEW操作系列 文章目录 系列文章目录前言五、特殊用法5.1 取值范围表示5.2 对输入值取值范围进行限定5.3 控制多个While循环停止运行。5.4 获取按钮上的文本5.5 获取按钮上的文本【进阶】 六、使用步骤1.引入库2.读入数据 七、其余功能7.…

机器学习笔记——决策树

定义 决策树是一种可以用来解决回归和分类的问题的算法 决策树使用树形结构&#xff0c;通过叶子节点上的条件层层推理&#xff0c;得到最终的结果 例如&#xff1a;通过上面的简单决策&#xff0c;我们可以通过形状这一条件决策出水果属于哪一类。 决策树的学习结果和取什么规…

RK3588+MIPI+GMSL+AI摄像机:自动车载4/8通道GMSL采集/边缘计算盒解决方案

RK3588作为目前市面能买到的最强国产SOC&#xff0c;有强大的硬件配置。在智能汽车飞速发展&#xff0c;对图像数据矿场要求越来越多的环境下&#xff0c;如何高效采集数据&#xff0c;或者运行AI应用&#xff0c;成为刚需。 推出的4/8通道GMSL采集/边缘计算盒产品满足这些需求…

鸿蒙(HarmonyOS)自定义Dialog实现时间选择控件

一、操作环境 操作系统: Windows 11 专业版、IDE:DevEco Studio 3.1.1 Release、SDK:HarmonyOS 3.1.0&#xff08;API 9&#xff09; 二、效果图 三、代码 SelectedDateDialog.ets文件/*** 时间选择*/ CustomDialog export struct SelectedDateDialog {State selectedDate:…

解开基于大模型的Text2SQL的神秘面纱

你好&#xff0c;我是 shengjk1&#xff0c;多年大厂经验&#xff0c;努力构建 通俗易懂的、好玩的编程语言教程。 欢迎关注&#xff01;你会有如下收益&#xff1a; 了解大厂经验拥有和大厂相匹配的技术等 希望看什么&#xff0c;评论或者私信告诉我&#xff01; 文章目录 一…

环境搭建-Windows系统搭建Docker

Windows系统搭建Docker 一、系统虚拟化1.1 启用虚拟化2.2 启用Hyper-v并开启虚拟任务 三、安装WSL3.1 检验安装3.2 安装WSL 四、Docker安装4.1 Docker安装包下载4.2 Docker安装4.3 运行docker Desktop 五、Docker配置5.1 打开Docker配置中心5.2 配置Docker国内镜像 六、使用 一…

提高爬虫稳定性:解决代理IP频繁掉线的完整指南

当代理IP在爬虫中频繁掉线时&#xff0c;我们先要了解出现问题的可能原因&#xff0c;这不仅限于技术性因素&#xff0c;还涉及操作策略和环境因素。只有在找到具体原因后&#xff0c;才能针对问题类型从源头解决IP掉线问题。 一、问题原因&#xff1a; 1. 代理IP质量问题导致…

vue3前端开发-小兔鲜项目-form表单的统一校验

vue3前端开发-小兔鲜项目-form表单的统一校验&#xff01;实际上&#xff0c;为了安全起见&#xff0c;用户输入的表单信息&#xff0c;要满足我们的业务需求&#xff0c;参数类型等种种标准之后&#xff0c;才会允许用户向服务器发送登录请求。为此&#xff0c;有必要进行一次…

通过限制访问,实现纯私有Docker镜像

怎么会不过审呢?没有敏感信息呀。 For obvious reasons,Many Docker image repositories are inaccessible,The official warehouse has also been filtered by the firewall,So write about how to build a self use Docker image using CloudFlares Workers and Pages. …

【第二天】计算机网络 HTTP请求报文和响应报文是什么样的 HTTP请求方式有哪些 GET请求和POST请求的区别

HTTP请求报文和响应报文是什么样的&#xff1f; 我去&#xff0c;以前都没怎么研究过这个。 客户端发送一个请求给服务器&#xff0c;服务器根据请求报文中的信息进行处理&#xff0c;并将处理结果放到响应报文中返回给客户端。 URL HTTP使用URL (Uniform Resource Locator&…

vscode 连接WSL子系统方法

1、在应用商店中安装wsl子系统&#xff1a;Ubuntu22.04 2、安装WSL扩展 3、打开vscode命令面板(左下角设置中)&#xff1b;输入wsl&#xff0c; 选择&#xff1a;Remote Explorer: Focus on WSL目标 view 这样就连接上了。。。。。 有时这个会没有这个链接箭头&#xff0c;可…

SSIS_SQLITE

1.安装 SQLite ODBC 驱动程序 2.添加SQLite数据源 在“用户DSN”或“系统DSN”选项卡中&#xff0c;点击“添加”。选择“SQLite3 ODBC Driver”&#xff0c;然后点击“完成”。在弹出的配置窗口中&#xff0c;设置数据源名称&#xff08;DSN&#xff09;&#xff0c;并指定S…