二叉树(3)——堆的应用

1 堆排序

  • 堆排序是一个选择排序

这里我们可以直接用前面所讲的,先将数组中的数根据插入都插入到堆里,然后再一个一个取Top堆顶元素。但是我们要知道,这样做有两个不好的地方:

  • 如果我们事先并没有实现堆的插入删除,就要重新写代码
  • 空间复杂度太高

这里我们可以用以下思路。

思路

1、建堆:直接将数组建堆。先假设第一个数就在堆里,然后把后面的数依次向上调整。

  • 本质:模拟堆插入的过程
  • 升序建大堆,降序建小堆  要重点理解!!!
  • 时间复杂度:N*logN

2、向下调整:先将首尾交换,然后将交换过来的新根向下调整。(最后一个元素不参与调整)一直循环这个过程,直到所有的数都交换完毕。

  • 本质:模拟堆删除的过程
  • 时间复杂度:(N-1)*logN

总时间复杂度:O(N*logN)

代码实现 

这里举例升序。 

向上调整建堆

void HeapSort(int* a, int n)
{// O(N*logN)//向上调整建堆/*for (int i = 1; i < n; i++){AdjustUp(a, i);}*/// O(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;}
}int main()
{int a[10] = { 4, 6, 2, 1, 5, 8, 2, 9 };int size = sizeof(a) / sizeof(a[0]);HeapSort(a, size);for (int i = 0; i < size; i++){printf("%d ", a[i]);}return 0;
}

 大堆的向上向下调整代码实现

void Swap(HPDataType* p1, HPDataType* p2)
{HPDataType tmp = *p1;*p1 = *p2;*p2 = tmp;
}void AdjustUp(HPDataType* a, int child)
{int parent = (child - 1) / 2;//while (parent >= 0) 不能这样写,因为parent不可能<0while (child > 0) //用child判断{if (a[child] > a[parent]){Swap(&a[child], &a[parent]);//往上走child = parent;parent = (child - 1) / 2;//child = (child - 1) / 2;//parent = (parent - 1) / 2;}else{break;}}
}void AdjustDown(int* a, int size, int parent)
{int child = parent * 2 + 1;while (child+1 < size && child < size){if (a[child + 1] > a[child]){++child;}if (a[child] > a[parent]){Swap(&a[child], &a[parent]);parent = child;child = parent * 2 + 1;}else{break;}}}

注意

向下调整建堆

在实现HeapSort函数时,可以直接用向上调整建堆,也就是思路里写的那种办法。但是这里用向下调整建堆更加方便。从倒数第一个非子叶,也就是最后一个节点的父亲开始依次(以上的数)向下调整,这样就能建立出来一个小堆或者大堆。

//向下调整建堆for (int i = (n-1-1)/2; i >= 0; --i){AdjustDown(a, n, i);}

 两大优势:

  • 可以只写一个向下调整就解决了堆排序,而不需要用到向上排序
  • 时间复杂度为O(N),效率高

 2 Top K问题

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

思路

1.、用数据集合中前K个元素来建堆
  • 前k个最大的元素,则建小堆
  • 前k个最小的元素,则建大堆
2、用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素。
3、将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。

代码实现 

这里求前k个最大的元素——小堆。向上向下调整的代码不再赘述。

void CreateNDate()
{// 造数据int n = 10000000;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){//写10000000个小于10000000的数int x = (rand()+i) % 10000000;fprintf(fin, "%d\n", x);}fclose(fin);
}void PrintTopK(const char* file, int k)
{FILE* fout = fopen(file, "r");if (fout == NULL){perror("fopen error");return;}// 开辟数组空间,建一个k个数小堆int* minheap = (int*)malloc(sizeof(int) * k);if (minheap == NULL){perror("malloc error");return;}// 读取前k个,建小堆for (int i = 0; i < k; i++){fscanf(fout, "%d", &minheap[i]);AdjustUp(minheap, i);}int x = 0;//读取后面的数比较进堆while (fscanf(fout, "%d", &x) != EOF){if (x > minheap[0]){minheap[0] = x;AdjustDown(minheap, k, 0);}}//打印前k个数for (int i = 0; i < k; i++){printf("%d ", minheap[i]);}printf("\n");free(minheap);fclose(fout);
}int main()
{CreateNDate(); //创造数据PrintTopK("Data.txt", 5); //取文件中最大的前5个数return 0;
}

注意

  • 打开文件、写文件、关闭文件
  • 随机数、随机数的种子、产生随机数
  • 随机数最多3万个!!在int x = (rand()+i) % 10000000;中,rand()后面+i可以有效的减少产生重复值。
  • 如果产生的随机数在x以内:%x

那么问题来了:我们该如何确保打印出来的5个数据就是最大的五个数据呢? 

  • 去文件里面修改5个值,使他们大于1000万,这样这5个值就一定是最大的5个值了,然后查看打印出来的是否是修改后的5个数据。

 

3 建堆的时间复杂度分析 

向下调整建堆

O(N)

向上调整建堆

O(N*logN)≈O(N)

 

向下调整快的原因:

  • 向下调整是节点少的调整次数多,节点多的调整次数少,且最后一行不参与调整 。
  • 向上调整是节点多调整次数也多,节点少调整次数也少,且最后一行参与调整 。

 

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

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

相关文章

回归预测 | Matlab实现POA-BP鹈鹕算法优化BP神经网络多变量回归预测

回归预测 | Matlab实现POA-BP鹈鹕算法优化BP神经网络多变量回归预测 目录 回归预测 | Matlab实现POA-BP鹈鹕算法优化BP神经网络多变量回归预测预测效果基本描述程序设计参考资料 预测效果 基本描述 1.Matlab实现POA-BP鹈鹕算法优化BP神经网络多变量回归预测&#xff08;完整源码…

【WebSocket】微信小程序原生组件使用SocketTask 调用星火认知大模型

直接上代码 微信开发者工具-调试器-终端-新建终端 进行依赖安装 npm install base-64 npm install crypto-js 然后顶部工具栏依次点击 工具-构建npm // index.js const defaultAvatarUrl https://mmbiz.qpic.cn/mmbiz/icTdbqWNOwNRna42FI242Lcia07jQodd2FJGIYQfG0LAJGFxM4FbnQ…

基于ESP-WROOM-32的双串口通信并显示到OLED显示屏上

目录 开发板引脚图 Arduino环境配置1.ESP32开发版下载2.Arduino开发板选择 -> ESP32 Dev Module3.安装驱动库 接线图Arduino代码现象演示 开发板 ESP-WROOM-32 引脚图 Arduino环境配置 1.ESP32开发版下载 选择 esp32 by Espressif Systems 2.Arduino开发板选择 -> E…

绕过安全狗

本节我们想要绕过的安全狗版本为v4.023957 &#xff0c;它是网站安全狗的Apache版。 首先搭建环境。渗透环境选用DVWA漏洞集成环境&#xff0c;下载地址 为http://www.dvwa.co.uk/ 。DVWA是一款集成的渗透测试演练环境&#xff0c;当刚刚入门 并且找不到合适的靶机时&#xff…

pwn学习笔记(1)前置基础

pwn学习笔记&#xff08;1&#xff09; &#xff08;1&#xff09;pwn简介&#xff1a; ​ 以下来自于百度百科&#xff1a;”Pwn”是一个黑客语法的俚语词&#xff0c;是指攻破设备或者系统发音类似“砰”&#xff0c;对黑客而言&#xff0c;这就是成功实施黑客攻击的声音—…

百面嵌入式专栏(面试题)内存管理相关面试题1.0

沉淀、分享、成长,让自己和他人都能有所收获!😄 📢本篇我们将介绍内存管理相关面试题 。 一、内存管理相关面试题 page数据结构中的_refcount和_mapcount有什么区别?匿名页面和高速缓存页面有什么区别?page数据结构中有一个锁,我们称为页锁,请问trylock_page()和loc…

async/await使用过程中,要注意的问题

问: const getData async () >{ console.log(触发了getData接口) let resultData await getActivityInfo(activityId); console.log(resultData,resultData) let id resultData.id; let shareImg resultData.shareImg let shareSubtitle resultData.shareSubtit…

RabbitMQ-4.MQ的可靠性

MQ的可靠性 4.MQ的可靠性4.1.数据持久化4.1.1.交换机持久化4.1.2.队列持久化4.1.3.消息持久化 4.2.LazyQueue4.2.1.控制台配置Lazy模式4.2.2.代码配置Lazy模式4.2.3.更新已有队列为lazy模式 4.MQ的可靠性 消息到达MQ以后&#xff0c;如果MQ不能及时保存&#xff0c;也会导致消…

C# CAD交互界面-自定义面板集-添加快捷命令(五)

运行环境 vs2022 c# cad2016 调试成功 一、引用 using Autodesk.AutoCAD.ApplicationServices; using Autodesk.AutoCAD.Runtime; using Autodesk.AutoCAD.Windows; using System; using System.Drawing; using System.Windows.Forms; 二、代码说明 [CommandMethod("Cre…

恒创科技:香港 BGP 服务器网络连通性如何测试?

随着互联网的快速发展&#xff0c;网络连通性测试变得越来越重要。网络连通性测试的目的是确定网络设备之间的连接是否正常&#xff0c;以及数据包是否能够在网络中顺利传输。本文将介绍一种简单易行的香港 BGP 服务器网络连通性的测试方法&#xff0c;利用tracer测试工具。这里…

vue3项目中使用mapv

vue3项目中使用mapv mapv是百度地图官方提供的地图数据可视化开源项目&#xff0c;提供了很多效果酷炫的绘图api mapv地址在这里&#xff0c;示例图在这里 先解释为什么要用mapv echarts画的地图&#xff0c;都是行政区划&#xff0c;就算是geo地图&#xff0c;也只能在行政…

MPLS——多协议标签交换

目录 1 多协议标签交换 MPLS 1.1 MPLS 的工作原理 1.1.1 MPLS 工作特点 1.1.2 MPLS 协议的基本原理 1.1.3 MPLS 的基本工作过程 1.2 转发等价类 FEC 1.2.1 FEC 用于负载平衡 1.3 MPLS 首部的位置与格式 1.3.1 MPLS 首部的位置 1.3.2 MPLS 首部的格式 1.4 新一代的…