二叉树_堆(下卷)

news2024/9/19 9:25:31

前言

接前面两篇的内容,接着往下讲二叉树_堆相关的内容。

正文

那么,回到冒泡排序与堆排序的比较。

我们知道冒泡排序的时间复杂度为 O ( N 2 ) O(N^2) O(N2),这个效率是不太好的。

那么,我们的堆排序的时间复杂度如何呢?

由于堆排序中我们使用到向下和向上调整,所以我们要先看看这两个算法的时间复杂度。

我们先看向上调整,主要看的是最多循环次数,如果我们的二叉树有k层,最大结点数为n,我们已经知道根据二叉树的性质: 2 k − 1 = n 2^k-1=n 2k1=n; k = l o g 2 ( n + 1 ) k=log_2(n+1) k=log2(n+1)

我们的向上调整的最差情况是和层次有关的。所以最后我们的向上调整算法的时间复杂度就为 O ( l o g n ) O(logn) O(logn)

而在这里我们循环n次向上调整,所以堆排序中建堆这一步的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)

我们再看后面这一步的时间复杂度。很明显,我们得看向下调整的时间复杂度。

因为向下调整也是和层次有关,我们可以粗估时间复杂度也为 O ( l o g n ) O(logn) O(logn)

那么最后我们的堆排序的时间复杂度为 O ( n l o g n ) O(nlogn) O(nlogn)+ O ( l o g n ) O(logn) O(logn),因为取的是对结果影响最大的那个,所以堆排序最后我们粗估的时间复杂度就为 O ( n l o g n ) O(nlogn) O(nlogn)

建堆的时间复杂度到底是不是 O ( n l o g n ) O(nlogn) O(nlogn),有待考证。

可以看看上面不同复杂度对比的图,发现冒泡排序的效率是比堆排序差很多的。

但是,我们仔细分析一下向上调整的时间复杂度,发现并不是我们刚才说的这么简单,因为我们的n在变化的过程中,需要交换的次数也是变化的。

在具体分析向上调整算法建堆的时间复杂度之前,我们先来说一个东西:这个是我们的向上调整算法建堆,其实我们还可以由向下调整方法来建堆。


向下调整算法建堆

(以大堆为例)

我们还是从堆顶也就是数组最前面的数据开始调整,要将堆顶的数据向下调整意味着下面的数据必须是有效的大堆。

所以我们遇到这样一个问题,为了将17向下调整,得保证它的子树是大堆;而我们要向下调整孩子结点20时,得保证20的子树是大堆……

那么我们可以改变一下思路,从最后一个结点的父节点开始向下调整,大的往上放建大堆。

i就是我们目前要向下调整的下标,i首先从最后一个结点的父节点开始;调整完后i–来到20的位置,向下调整后再次i–来到了17的位置,向下调整,这里会调整两层。最后我们就得到了一个大堆。

所以我们其实是从子树开始调整,然后保证堆顶的子树为堆后再将其进行向下调整。

代码:

可以看到,我们的大堆就成功建成了。

这就是我们的向下调整算法建堆。

可以看到向上调整算法建堆时我们就是从头(第一个数据)开始,而向下调整算法建堆我们则是从尾开始(最后一个结点的父节点)。


向上调整算法建堆VS向下调整算法建堆

这两种建堆算法,哪一种的时间复杂度更好呢?

我们需要数学推理。

向下调整算法建堆的时间复杂度推理

(我们只看到h-1层为止,因为最后一层不需要向下调整;h代表的是总层数;需要移动的层数是最坏情况的移动层数)

如图,要计算移动的次数是由结点的数量和移动的层次共同决定的,我们在二叉树的性质中可以得知每一层的最大节点数(每一层的节点数要移动的层数是不同的所以我们要分开去看),而层数我们也是可以知道的。

我们时间复杂度计算的是最坏的情况,所以我们可以这样计算需要移动的总步数: 每层节点个数 × 向下调整次数 每层节点个数×向下调整次数 每层节点个数×向下调整次数,最后加在一起。

然后我们通过错位相减,化简,再通过二叉树性质,代入可以得到 T ( n ) = n − l o g 2 ( n + 1 ) T(n)=n-log_2(n+1) T(n)=nlog2(n+1)。我们知道时间复杂度最后取对结果影响最大的那个,所以向下调整算法建堆我们最后得到的时间复杂度为 O ( n ) O(n) O(n)

(详细推理见下图)

用我们刚才乍一看的方法,外层循环大概为O(n),内层的AdjustDown方法根据二叉树的性质: 2 k − 1 = n 2^k-1=n 2k1=n; k = l o g 2 ( n + 1 ) k=log_2(n+1) k=log2(n+1),为O(logn),所以我们推测为O(nlogn),但实际上根据数学推导却是O(n)。

可以看到,我们如果乍一看,其实错误地算大了许多。

向上调整算法建堆的时间复杂度推理

同样的,因为是最坏情况,我们同样是计算每层的节点个数×每层结点要移动的层数,最后相加。

根节点无需向上调整,从第二层开始调整。

最后同样是错位相减、化简,利用性质替换,我们得到向上调整算法建堆的时间复杂度为 O ( n ∗ l o g 2 n ) O(n*log_2n) O(nlog2n)

(详细推理)

我们可以看出,对于向上调整算法建堆来说,越往下结点数越多,需要移动的层次也越多;向下调整算法建堆则越往上虽然要移动层次越多,但是节点数却越少。

移动层数越多×节点数越多,显然要比移动层次越多×节点数越少来得多。

所以我们凭借这个规律我们其实也可以就看出向下调整算法建堆的时间复杂度应该是更低的。

所以,无论是从时间复杂度的结果还是从这个规律来看,向下调整算法建堆的时间复杂度是更好的


过了这么久我们再说回堆排序,所以比较好的堆排序方法就是使用向下调整算法建堆加上循环将堆顶数据与当前的最后一个数据交换。

我们可以知道堆排序的时间复杂度就为向下调整算法建堆的O(n),加上后一个循环中用到向下调整方法复杂度为O(logn),所以整个循环复杂度为O(nlogn),O(n)+O(nlogn),取大的那个,所以堆排序的时间复杂度为O(n*logn)。

到此,本文结束,祝阅读愉快O(∩_∩)O

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

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

相关文章

Linux:进程概述(什么是进程、进程控制块PCB、并发与并行、进程的状态、进程的相关命令)

进程概述 (1)What(什么是进程) 程序:磁盘上的可执行文件,它占用磁盘、是一个静态概念 进程:程序执行之后的状态,占用CPU和内存,是一个动态概念;每一个进程都有一个对应的进程控制块…

云计算复习--分布式存储系统

分布式存储 分布式存储系统是一种将数据分散在多个独立节点上,并通过网络进行数据传输和访问的存储系统 分布式存储的特点:可扩展性、高可用性、容错性、高性能等。分布式存储系统能够水平扩展存储容量和性能,提供持续可用的数据存储服务&am…

【在开发小程序的时候如何排查问题】

在开发小程序的时候如何排查问题 在最近开发小程序的时候,经常出现本地在浏览器中调试没有问题,但是一发布到预发环境就出现各种个样的问题 手机兼用性问题 有时候会出现苹果🍎手机键盘弹出,导致ui界面高度出现异常边界问题&#…

for循环打印1~10之间数字

对于for循环之前了解不够的同学可以看之前的我写的介绍 我们这里直接上代码 #include<stdio.h> int main() {int i 0;for (i 1; i < 11; i){printf("%d\n", i);}return 0; }

0724_驱动1 字符设备驱动内部实现

一、字符设备驱动内部实现工作原理 二、分布实现字符设备驱动API接口 分配对象&#xff1a; #include <linux/cdev.h> struct cdev *cdev_alloc(void) 函数功能&#xff1a;分配对象struct cdev *结构体指针 参数&#xff1a;无 返回值&#xff1a;成功返回struct cdev *…

人工智能类——计算机科学与技术

计算机科学与技术是一个非常大的门类。目前计算机科学与技术类招生的专业主要有计算机科学与技术、软件工程、网络工程、信息安全、物联网工程等&#xff0c;后面的几个专业是计算机科学与技术的重要分支&#xff0c;而这个门类的其他分支并没有单列出来一个本科专业&#xff0…

实战|EDU挖掘记录-某学校sql注入挖掘记录

本文来源无问社区&#xff0c;更多实战内容&#xff0c;渗透思路尽在无问社区http://www.wwlib.cn/index.php/artread/artid/9755.html 某大学的办公系统&#xff0c;学号是我从官网下载的优秀人员名单找到的&#xff0c;初始密码为姓名首字母加身份证后六位&#xff0c;我是社…

高级及架构师高频面试题-基础型

1、设计模式有哪些原则&#xff08;待解释的更直白&#xff09; 单一职责原则&#xff1a;一个类或方法应只负责一项职责&#xff0c;避免一个类因为多个变化原因而改变。开闭原则&#xff1a;软件实体应对扩展开放&#xff0c;对修改封闭。比如要增加用户类别的时候可以新增一…

Java高频面试题分享

文章目录 1. 策略模式怎么控制策略的选取1.1 追问&#xff1a;如果有100种策略呢&#xff1f;1.2 追问&#xff1a;什么情况下初始化Map 2. 什么是索引&#xff1f;什么时候用索引&#xff1f;2.1 追问&#xff1a;怎么判断系统什么时候用量比较少2.2 追问&#xff1a;如何实时…

树 ----- 基础学习

树 树&#xff1a;n&#xff08;n>0&#xff09;个结点的有限集合。n 0 ,空树。 在任意一个非空树中&#xff0c; 1&#xff0c;有且仅有一个特定的根结点 2&#xff0c;当n>1 时&#xff0c;其余结点可分为m个互不相交的有限集合T1,T2,T3.。。。。Tm&#xff0c;其中每…

使用 uPlot 在 Vue 中创建交互式图表

本文由ScriptEcho平台提供技术支持 项目地址&#xff1a;传送门 使用 uPlot 在 Vue 中创建交互式图表 应用场景介绍 uPlot 是一个轻量级、高性能的图表库&#xff0c;适用于创建各种交互式图表。它具有丰富的功能&#xff0c;包括可自定义的轴、网格、刻度和交互性。本篇博…

脊髓损伤的小伙伴锻炼贴士

Hey小伙伴们~&#x1f44b; 今天要跟大家聊一个超燃又超温馨的话题&#xff01;&#x1f31f; 对于我们脊髓损伤的小伙伴们来说&#xff0c;保持身体活力&#xff0c;不仅是健康的小秘诀&#xff0c;更是拥抱美好生活的超能量哦&#xff01;&#x1f4aa; #脊髓损伤# 首先&…

【ffmpeg命令入门】Nginx的安装与制作HLS流媒体服务器

文章目录 前言Nginx简介Ubuntu安装Nginxffmpeg生成HLS流媒体1. 生成HLS流媒体命令说明 配置Nginxffplay播放m3u8 总结 前言 在数字内容传输和流媒体服务中&#xff0c;HLS&#xff08;HTTP Live Streaming&#xff09;已经成为一种流行的解决方案&#xff0c;特别是在视频直播…

FPGA FIFO IP核(2)- 配置与调用

前言 上上期介绍了FIFO IP核理论方面的一些内容&#xff0c;接下来开始进行FIFO IP核的配置和使用部分。 FIFO IP核再理解 关键点 先进先出&#xff1a;数据按顺序写入FIFO&#xff0c;先被写入的数据在读取的时候先被读出。 FIFO存储器没有地址线。 FIFO主要作为缓存&#…

C语言 | Leetcode C语言题解之第275题H指数II

题目&#xff1a; 题解&#xff1a; int hIndex(int* citations, int citationsSize) {int left 0, right citationsSize - 1;while (left < right) {int mid left (right - left) / 2;if (citations[mid] > citationsSize - mid) {right mid - 1;} else {left mi…

时效性知识点是否值得花时间学习和研究

新趋势 智能大模型训练成本与人才培养成本之间的博弈。 视频 录了个断断续续的视频&#xff1a; 编程简单吗&#xff1f;为什么技术型内容几乎停更了&#xff1f; 代码形式的程序 /** Created by ArduinoGetStarted.com** This example code is in the public domain** Tuto…

[算法]插入排序和希尔排序

这里简单的介绍一下插入排序和希尔排序的算法实现&#xff0c;为简单起见&#xff0c;排序为升序且排序的数组是整形数组。 一、插入排序 &#xff08;一&#xff09;、算法思路 把数组里的第一个元素视为有序的&#xff0c;然后取第二个元素与前面的元素作比较&#xff0c;如…

2024钉钉杯A题思路详解

文章目录 一、问题一1.1 问题1.2 模型1.3 目标1.4 思路1.4.1 样本探究1.4.2 数据集特性探究&#xff1a;1.4.3 数据预处理1.4.4 数据趋势可视化1.4.5 ARIMA和LSTM两种预测模型1.4.6 参数调整 二、问题二2.1 问题2.2 模型2.3 目标2.4 思路2.4.1 样本探究2.4.2 数据集特性探究2.4…

jenkins中shell脚本中使用构建参数化Groovy变量的四种方式

jenkins中shell脚本中使用构建参数化Groovy变量的四种方式: 以字符变量为例&#xff1a; 流水线代码&#xff1a; pipeline {agent {//label "${server}"label "${28}"}stages {stage(Hello) {steps {echo Hello Worldecho "${28}"echo "…

C语言-TCP通信创建流程

TCP通信创建流程 1. 客户端创建TCP连接 在整个流程中, 主要涉及以下⼏个接⼝socket() : 创建套接字, 使⽤的套接字类型为流式套接字connect() : 连接服务器send() : 数据发送recv() : 数据接收创建套接字 首先&#xff0c;我们需要创建套接字&#xff0c;套接字是通信的基础…