当前位置:首页 > 编程笔记 > 正文
已解决

【数据结构】堆的应用+TOP-K问题+二叉树遍历

来自网友在路上 169869提问 提问时间:2023-09-18 22:44:55阅读次数: 69

最佳答案 问答题库698位专家为你答疑解惑

在这里插入图片描述

欢迎来到我的:世界

希望作者的文章对你有所帮助,有不足的地方还请指正,大家一起学习交流 !


目录

  • 前言
  • 堆的时间复杂度
    • 向下调整算法的时间复杂度
    • 向上调整算法的时间复杂度
  • 堆的应用
    • 堆排序
    • TOP—K问题
    • 链式二叉树
      • 二叉树的节点:
      • 初始化节点
      • 实现链式二叉树
    • 二叉树的概念:
      • 二叉树的遍历
        • 前序遍历
        • 中序遍历
        • 后序遍历
        • 层序遍历
  • 总结

前言

该篇文章写到主要是:堆排序、 TOP-K问题、二叉树链式结构的实现、二叉树的遍历等等;如果有朋友还不太了解堆以及二叉树可以翻看我的上一篇博客:堆和二叉树的概念;
最后老铁们准备发车喽!!!


堆的时间复杂度

紧接上一篇博客,我们刚刚实现了堆的实现,还没有拿他做点有意义的事情呢 ,咱们马上开始👉
如果问你:建堆的时间复杂度是多少?

实现堆有有两种方法:向下调整算法和向上调整算法,但是这两种方法有区别吗?哪个算法的时间复杂度更好呢?
接下来我们来带着问题进入下方:

向下调整算法的时间复杂度

时间复杂度就是看其最坏的情况,因为堆是完全二叉树,而满二叉树也是完全二叉树,此处为了简化使用满二叉树来证明(时间复杂度本来看的就是近似值,多几个节点不影响最终结果):

在这里插入图片描述
在这里插入图片描述
由于我们已经知道满二叉树结点和层数的关系N=2^h-1可转化为h=log2(N+1)(ps:Log2(n+1)是log以2为底,n+1为对数)

知道了这层关系可以推出:
T(N)= N-log2(N+1)~ N (约等于)
所以向下调整算法的时间复杂度:O(N)

向上调整算法的时间复杂度

向上调整算法的时间复杂度比向下调整算法要慢;如何得出呢?
同样的情况,利用的满二叉树来估计其时间复杂度;
在这里插入图片描述
a1(1-q^n)/(1-q)
得出T(N)=2^h *(h-1) - 2*(1-2^h)进行化简:T(N)=2^h*(h+1)-2

可转化为:
T(N)=2^h*(h+1)-2=(N+1)*(log2(N+1)+1)-2(ps:Log2(n+1)是log以2为底,n+1为对数)
T(N)=(N+1)*(log2(N+1)+1)-2 ~ N*log2(N)(ps:Log2(N)是log以2为底,N为对数)
所以向上调整算法的时间复杂度是:O(N*logN)

堆的应用

堆排序

堆排序即利用堆的思想来进行排序,总共分为两个步骤:

1. 建堆
- 升序—建大堆
- 降序—建小堆
2. 利用堆删除思想来进行排序

建堆和堆删除中都用到了向下调整,因此掌握了向下调整,就可以完成堆排序。
就拿升序来说:
实现升序怎么完成呢?
首先要明白升序是建大堆;
在这里插入图片描述

在这里插入图片描述
具体代码实现:

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

TOP—K问题

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

1. 用数据集合中前K个元素来建堆
- 前k个最大的元素,则建小堆
- 前k个最小的元素,则建大堆
2. 用剩余的N-K个元素依次与堆顶元素来比较,不满足则替换堆顶元素

将剩余N-K个元素依次与堆顶元素比完之后,堆中剩余的K个元素就是所求的前K个最小或者最大的元素。
举个列子:有随机100万个数储存在堆中(条件:每个元素都在int的范围内),现在需要找出最大或最小的5个数,如果全部进行堆排序,计算机的要算炸了,肯定不行;这就需要我们上面的思路:
如果要求出这组数据中最大的前K个数,就取数据的前K个元素来建小堆,假设是在所有数据中最大的前K个;在剩下的n-k个数据中,依次对小堆的第一个元素进行比较,如果比小堆的第一个元素还小就不可能是所有数据中最大的K个中的一个,如果比小堆的第一个元素大,那就让其代替小堆第一个的位置,在进行向下调整,让小堆中最小的那个元素到堆顶来,然后就再次比较下一个,直到所有元素都比完,那就代表堆中剩余的K个元素就是所求的前K个最大的元素。

在这里插入图片描述
但是:这样就行了么?在100万个数字里,有什么依据肯定一定输出的就是所有元素中的前K个最大元素呢?
所以我们需要检测的话就需要赋值几个特定的值,假如在设定输出随机值的时候肯定会有其限制:在1~100万的范围里生成随机值,我们赋值几个大于100万的数字就可以判断有没有成功找出最大的K个值;
假如我设定几个值

	a[5] = 1000000 + 1;a[1231] = 1000000 + 2;a[531] = 1000000 + 3;a[5121] = 1000000 + 4;a[115] = 9999999;

代码的实现:

void PrintTopK(int* a, int n, int k)
{// 1. 建堆--用a中前k个元素建堆int i = 0;for (i = (k - 2) / 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--;}// 2. 将剩余n-k个元素依次与堆顶元素交换,不满则则替换for (i = n-k-1; i < n; i++){if (a[i] > a[0]){a[0] = a[i];Adjustdown(a, k, 0);//向下调整算法}}//打印出来for (i = 0; i < k; i++){printf("%d\n", a[i]);}
}void TestTopk()
{int n = 10000;int* a = (int*)malloc(sizeof(int) * n);if (a == NULL){perror("malloc");exit(-1);}srand(time(0));for (int i = 0; i < n; ++i){a[i] = rand() % 1000000;}int k = 5;a[5] = 1000000 + 1;a[1231] = 1000000 + 2;a[531] = 1000000 + 3;a[5121] = 1000000 + 4;a[115] = 9999999;PrintTopK(a, n, k);
}int main()
{TestTopk();return 0;
}

最后会打印出来:如果就是你设置的那K个值,那就代表已经实现了TOP-K问题

在这里插入图片描述

链式二叉树

在前面的文章中我们是使用数组的方式实现二叉树,虽然物理存储是和二叉树一样的,但是并不直观的可以感受到;下面我们来使用链表的方式来实现堆,可以更直观的实现二叉树;

二叉树的节点:

二叉树数的每个节点至多有两个度,所以只需要一左一右指针用来链接其子节点就可以完成链式二叉树;

typedef int Treetypedef;typedef struct TreeNode
{Treetypedef val;struct TreeNode* left;struct TreeNode* right;
}TNode;

初始化节点

初始化节点,设置节点值;

TNode* Node(Treetypedef n)
{TNode* ret = (TNode*)malloc(sizeof(TNode));if (ret == NULL){perror("malloc");exit(-1);}ret->left = NULL;ret->right = NULL;ret->val = n;
}

实现链式二叉树

在学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。由于现在大家对二叉树结构掌握还不够深入,为了降低大家学习成本,此处手动快速创建一棵简单的二叉树,快速进入二叉树操作学习,等二叉树结构了解的差不多时,我们反过头再来研究二叉树真正的创建方式。

假如要实现下列二叉树:
在这里插入图片描述

    struct TreeNode* node1 = Node(10);struct TreeNode* node2 = Node(15);struct TreeNode* node3 = Node(56);struct TreeNode* node4 = Node(25);struct TreeNode* node5 = Node(30);struct TreeNode* node6 = Node(70);node1->left = node2;node1->right = node3;node2->left = node4;node2->right = node5;node3->left = node6;

注意:这并不是建造链式二叉树的方式,只是为了今天二叉树的遍历问题,而简易直接搭建的链式二叉树。

二叉树的概念:

二叉树有两种是:
1.空树。
2.由根节点,根节点的左子树、根节点的右子树组成的。

在这里插入图片描述
从概念中可以看出,二叉树定义是递归式的,因此后序基本操作中基本都是按照该概念实现的。

二叉树的遍历

二叉树的遍历就是依次对二叉树中的节点进行相应的操作,并且每个节点只操作一次。
遍历可分成一下几种:
1. 前序遍历:先访问根节点再访问左子树最后访问右子树;
2. 中序遍历:先访问左子树再访问根节点最后访问右子树;
3. 后序遍历:先访问左子树再访问右子树最后访问根节点;
4. 层序遍历:以层来访问,一层一层往下访问,每一层是从左往右访问;

前序遍历

先访问根节点再访问左子树最后访问右子树
访问顺序:根节点—左子树—右子树

// 二叉树前序遍历
void PreOrder(TNode* root)
{if (root == NULL){printf("NULL ");return;}printf("%d ", root->data);PreOrder(root->left);PreOrder(root->right);
}

在这里插入图片描述

中序遍历

先访问左子树再访问根节点最后访问右子树
访问顺序:左子树—根节点—右子树

// 二叉树中序遍历
void InOrder(TNode* root)
{if (root == NULL){printf("NULL ");return;}InOrder(root->left);printf("%d ", root->val);InOrder(root->right);
}

在这里插入图片描述

后序遍历

先访问左子树再访问右子树最后访问根节点
访问顺序:左子树—右子树—根节点

// 二叉树后序遍历
void PostOrder(TNode* root)
{if (root == NULL){printf("NULL ");return;}PostOrder(root->left);PostOrder(root->right);printf("%d ", root->val);
}

在这里插入图片描述

层序遍历

以层来访问,一层一层往下访问,每一层是从左往右访问

如其访问结果应该是:
10 15 56 25 30 70 NULL NULL NULL NULL NULL NULL NULL

该便利需要利用队列来一起实现,在本篇文章就不详解了,在下一篇中我会详细解释;


总结


到了最后:感谢支持

我还想告诉你的是:
------------对过程全力以赴,对结果淡然处之
也是对我自己讲的

查看全文

/2175413.html

相关文章:

  • 数据库连接工具Chat2DB介绍
  • C# 流Stream详解(3)——FileStream源码
  • Vue Grid Layout -️ 适用Vue.js的栅格布局系统,在vue3+上使用
  • [maven] maven 创建 web 项目并嵌套项目
  • vue3-vant4-vite-pinia-axios-less学习日记
  • 二叉树题目:层数最深叶子结点的和
  • Java手写约瑟夫问题算法和约瑟夫问题算法应用拓展案例
  • innovus: 各种padding一勺烩
  • 简单的分析下dart实现grpc客户端的流程,以helloworld为例
  • stm32--独立看门狗
  • GcExcel:Java 应用创建、修改和保存 Excel 电子表格 -Crack
  • 腾讯mini项目-【指标监控服务重构】2023-08-19
  • leetcode363周赛
  • new/delete, malloc/free 内存泄漏如何检测
  • 无涯教程-JavaScript - ODD函数
  • 阿里云无影电脑:免费体验无影云电脑3个月
  • 嵌入式学习笔记(25)串口通信的基本原理
  • 前后端分离技术逐步深入,让你更加深入理解Nginx+Tomcat
  • Linux学习第11天:字符设备驱动开发:一字一符总见情
  • windows彻底卸载unity
  • 前端html原生页面兼容多端H5和移动端适配方案
  • 系统性能调优:提升服务器响应速度
  • PHP通过pem文件校验签名异常
  • 【C++ Exceptions】Catch exceptions by reference!
  • 科技资讯|苹果虚拟纸可在Vision Pro中为广告、书籍等提供MR内容和动画
  • webpack静态资源上传到CDNS (阿里云 OSS,亚马逊 AWS S3,七牛云 Qiniu Cloud Kodo)webpack-plugin-cdns
  • VMware workstation 中centos7虚拟机在nat模式下怎么配置网卡,指定我想要的IP并且可以联网
  • Flask 使用 JWT(一)
  • 【ant-design-vue】ant-design-vue在uniapp使用时,auto-import失败报错
  • 一文通览腾讯云大数据ES、数据湖计算、云数据仓库产品新版本技术创新
  • cuda以及pytorch安装
  • Xilinx FPGA 7系列 GTX/GTH Transceivers (2)--IBERT
  • oracle创建数据库以及用户,并导入dmp格式数据
  • 每个高级前端工程师都应该知道的前端布局
  • 微软发现影响 Linux 和 macOS系统的 ncurses 库漏洞
  • 前后端开发接口联调对接参数
  • 线性代数的本质(一)——向量空间
  • Maven 工具学习笔记(基础)
  • reg与wire的用法,证明reg可以在右边,wire型在左边,来作组合逻辑处理。
  • 【JDK 8-函数式编程】4.5 Predicate
  • html网页制作期末大作业-网上花店商城html+css+javascript
  • 2023年11月25日PMP报名正式开始!附操作指南
  • 伦敦银时走势与获利机会
  • 【数据结构】单值二叉树 相同的树 翻转二叉树(五)
  • 从0搭建夜莺v6基础监控告警系统(一):基础服务安装
  • three.js——模型对象的使用材质和方法
  • Java手写红黑树
  • 华为HCIA(四)
  • MyBatis面试题(一)
  • ARM cortex-A7核LED灯点灯实验
  • vue学习-01vue入门
  • K8s(Kubernetes)学习(六)——Ingress
  • 8种LED显示屏的安装方式
  • zabbix学习1--zabbix6.x单机
  • 一文了解水雨情在线监测站的优势
  • QSlider风格设置
  • GaussDB(DWS)云原生数仓技术解析:湖仓一体,体验与大数据互联互通
  • 项目性能优化 - 并发编程合并文章详情页的 HTTP 请求次数
  • linux基础篇
  • MATLAB中filloutliers函数用法
  • 蓝桥杯2023年第十四届省赛真题-买瓜--Java题解
  • OpenText EnCase Mobile Investigator 查看、分析和报告被调查手机的证据
  • 83 # 静态服务中间件 koa-static 的使用以及实现
  • 计算机网络第四章——网络层(下)
  • 09MyBatisX插件
  • JMeter基础 —— 使用Badboy录制JMeter脚本!
  • 蓝牙核心规范(V5.4)10.1-BLE 入门笔记(1)
  • Java实现图书管理系统
  • 评价模型:层次分析法
  • 【免费内网穿透】cpolar从0开始使用
  • 面试中常见的算法题和其python实现
  • flask+python快速搭建
  • 手把手教你搭建农产品商城小程序:详细步骤解析
  • 信息化助力高校教育统计数据质量的提升
  • 4G模块驱动移植
  • 软件测试团队必看:测试指标 TOP 3 榜单
  • 【seata】引入seata导致原本自定义实现的RequestInterceptor失效
  • SSM - Springboot - MyBatis-Plus 全栈体系(七)
  • TypeScript逆变 :条件、推断和泛型的应用
  • OpenStack创建云主机并连接CRT
  • 04Spring的核心配置文件
  • 构建个人图床云盘—EasyImage的简单部署及远程访问配置
  • 计算机网络选择题笔记
  • 【AI语言大模型】文心一言功能使用介绍
  • JSP ssm 网上求职管理系统myeclipse开发mysql数据库springMVC模式java编程计算机网页设计
  • 2021年电工杯数学建模A题高铁牵引供电系统运行数据分析及等值建模求解全过程论文及程序
  • List 获取前N条数据
  • 虹科分享 | 来自Redis7.2的一封信:亲爱的Programmer,当你......
  • 抖音小店经营指南:在兴趣电商背景下打造成功的抖音店铺
  • ts 泛型基础介绍
  • AOSP Android 系统源码编译出的framework.jar和android.jar之间的区别
  • 【实战】H5 页面同时适配 PC 移动端 —— 旋转横屏
  • 代码随想录算法训练营第55天 | ● 392.判断子序列 ● 115.不同的子序列
  • 构建本地Web小游戏网站:Ubuntu下的快速部署与公网用户远程访问
  • Unity中UI组件对Shader调色
  • PostgreSQL serial类型
  • redis 哨兵(sentinel)机制
  • 一键搭建免费eXtplorer在线文件管理器,远程登录实现文件随身存储
  • 计算机网络第五章——传输层(下)
  • 欧拉操作系统在线安装mysql8数据库
  • 99%的人还看了

    猜你感兴趣

    版权申明

    本文"【数据结构】堆的应用+TOP-K问题+二叉树遍历":http://eshow365.cn/6-8934-0.html 内容来自互联网,请自行判断内容的正确性。如有侵权请联系我们,立即删除!