《数据结构与算法之美》学习笔记二

前言:本篇文章介绍了一下二叉树中的基本知识点,包括二叉树的种类、二叉树的存储方式以及二叉树的深度和广度优先遍历;以及《数据结构与算法》中对于数组的讲解记录,只记录了本前端能看懂的🤓,还有很多知识点是我看不懂的,后端老师请自行探索吧。

一、二叉树

最近一直在刷《代码随想录》二叉树相关的题目,总结一下非常基本的一些知识点

(一)二叉树的种类

1、满二叉树

二叉树上只有度为0和度为2的节点,并且度为0的节点都在同一层,这样的二叉树叫做满二叉树。
就是所有的节点都满满当当的。假设二叉树的深度为k,那么满二叉树的节点数为 2^k -1
在这里插入图片描述

2、完全二叉树

完全二叉树除了最底层没有填满,其他层的节点都是满的。最后一层的节点集中在左侧。
在这里插入图片描述

3、二叉搜索树

二叉搜索树是有顺序的树。
对于二叉搜索树的所有节点,如果左子树不为空,那么左子树上所有节点值都小于节点值;如果右子树不为空,那额右子树上所有节点值都大于节点值。
在这里插入图片描述

4、平衡二叉树

它是一棵空树,或者左右子树的高度差不超过1
在这里插入图片描述

(二)二叉树的存储方式

1、使用指针的链式存储

链式存储就是用 TreeNode 这个数据类型存储,相信大家在刷力扣的时候见过很多次了。
在这里插入图片描述

3、使用数组的顺序存储

使用数组存储的顺序是按照层序遍历的顺序
在这里插入图片描述
假设节点的索引是 i,那么左节点的索引就是 i*2+1;右节点的索引就是 i*2+2

(三)二叉树的遍历

神一样的递归三部曲:
1、确定递归的参数和返回值
2、确定递归的终止条件
3、确定递归的单层逻辑

1、深度遍历

深度遍历的前中后序中的前中后,指的是中间节点出现的顺序

(1)前序

就是中左右的顺序
① 递归

const dfs = function (node) {if (!node) return;// 访问中间节点console.log(node);dfs(node.left);dfs(node.right);
}

② 迭代
前序遍历的访问顺序是 中左右,先访问中节点,使用栈暂存中节点的左右子节点,由于栈是先进后出的,所以应该先加入右节点,后加入左节点

var preorderTraversal = function (root) {const ans = [];if (!root) return ans;const stack = [root];while (stack.length) {const item = stack.pop();ans.push(item.val);item.right && stack.push(item.right);item.left && stack.push(item.left);}return ans;
};
(2)中序

顺序是 左中右
① 递归

const dfs = function (node) {if (!node) return;dfs(node.left);// 访问中间节点console.log(node);dfs(node.right);
}

② 迭代

// 中序遍历 左中右
// 其实递归就是一个模拟的过程
// 要先加左节点就要一直 .left 到达左叶子节点
// 所以要先将路过的节点存到stack里面
// 并且要用指针指向当前节点
var inorderTraversal = function (root) {const stack = [];const res = [];let cur = root;while (stack.length || cur) {if (cur) {stack.push(cur)// 一直找 .leftcur = cur.left;} else {// 出栈const item = stack.pop();res.push(item.val);cur = item.right;}}return res;
};
(3)后序

顺序是 左右中
① 递归

const dfs = function (node) {if (!node) return;dfs(node.left);dfs(node.right);// 访问中间节点console.log(node);
}

② 迭代
上面的前序遍历的迭代实现的是 中左右,后序遍历顺序是 左右中,那么只需要先把前序变成 中右左,然后再翻转最后得到的数组就可以了

var postorderTraversal = function (root) {const ans = [];if (!root) return ans;const stack = [root];while(stack.length){const cur = stack.pop();ans.push(cur.val);cur.left && stack.push(cur.left);cur.right && stack.push(cur.right);}return ans.reverse();
};
2、广度优先遍历

就是层序遍历,使用队列或者栈暂存

 // 使用队列保存每一层的节点
var levelOrder = function(root) {const ans = [];if(!root) return ans;const queue = [root];while(queue.length){const len = queue.length;for(let i=0;i<len;i++){const item = queue.shift();ans.push(item.val);item.left && queue.push(item.left);item.right && queue.push(item.right);}}return ans;
};

二、数组

这一节是《数据结构与算法之美》基础课的第一讲
数组是数据结构中最基本的概念,是我们每天都在用的数据结构,对于这个我们自认为简单又熟悉的数据结构,却有一个深刻而陌生的问题:
数组为什么从0开始编号呢?
下面就通过这一章的学习来解答这个问题,让我们对数组更亲切熟悉吧。

(一)基础概念

虽然大家对数组很熟悉,但是还是有必要用学术性的语言定义一下数组
数组(Array)是一种线性表数据结构。它用一组连续的内存空间,来存储一组具有相同类型的数据。
其中涉及到的线性表概念解释一下

1、线性表

线性表就是在排列上排成一条线的结构,它只有前后两个方向,线性表的种类:数组、列表、队列、栈等等
在这里插入图片描述

2、非线性表

就是数据排列不是线性的数据结果,数据不是简单的前后关系,比如二叉树、图、堆等
在这里插入图片描述

(三)数组的特性

1、随机访问

由于数组是在连续空间上存储的相同数据类型的数据,这种特性使得数组具有 随机访问 的能力,也就是可以根据数组的下标随机访问数组元素。那么这个特异功能是怎么实现的呢?
我们以一个长度为10的数组举例,计算机会为这个数组开辟长度为10的空间,假设分配的内存空间是 1000 ~ 1039,其中内存块的首地址 base_address 是1000
在这里插入图片描述
计算机会给每个内存单元分配地址,计算机通过寻找内存地址来寻找对应的数据,当计算机需要随机访问数组中的某个元素的时候,就会通过下面的寻址公式查找对应位置的数据

a[i]_address = base_address + i * data_type_size

其中 data_type_size 表示内存空间大小,对于我们的例子 int 类型来说,就是4个字节。
由于这种根据寻址公式查找数据的机制,数组可以支持时间复杂度为 O(1) 的随机访问。

2、插入删除速度慢

由于连续存储数据的这种机制,数组的插入和删除操作的速度会比较慢。

  • 插入操作
    先分析一下插入操作,要插入一个元素,就必须要把这个元素后面的元素都往后搬运一位,然后把元素放在指定位置。
    这样的时间复杂是多少呢?
    时间复杂度取决于要进行多少次数据操作。最好情况下,我们在数组的最后插入元素,那么不需要搬运其他元素,时间复杂度为 O(1),所以最好时间复杂度就是 O(1);最坏情况下,我们在数组的开头插入元素,所有的元素都需要往后搬运一位,最坏情况时间复杂度就是 O(n)。又由于插入的位置从 1 ~ n 的概率都是 1/n,所以平均时间复杂度是 O(1+2+...+n)/n = O(n)
    如果我们只是为了在索引为 k 的地方插入元素 a,有一个更省时的处理方式,就是把索引为 k 的元素搬到数组的最后,把 a 插入到位置 k,这其实就是快排的思想。

  • 删除操作
    其实删除操作和插入操作的分析过程是一样的,时间复杂度为 O(n)。
    如果我们要执行一系列的删除操作,例如要依次删除下面的 a、b、c,那么删除 a 的时候,b和c的搬运是不是就是浪费的?所以在删除操作中,我们可以先记录下打算删除哪个元素,并不真正的删除,等待一段时间后,再检查一下要删除的元素都有谁,批量进行删除。这就是 JVM 的垃圾回收的思想。好吧,本前端不会(傲娇.jpg)。
    在这里插入图片描述
    回到前面的问题:为什么数组都是从 0 开始编号呢?
    回顾一下寻址公式:

a[i]_address = base_address + i * data_type_size

数组的索引记录的其实是相对于 base_address 的偏移量,第一个元素就是在 base_address 的位置,如果数组从 1 开始编号,那么根据寻址公式随机访问元素的时候,都要进行 i-1 的操作,浪费一次计算,所以从 0 开始可以有效的提高随机访问数组元素的效率。当然最开始的 c 语言可能是出于这个目的,后来的编程语言可能是为了和 c 语言保持统一,干脆都从 0 开始编号。

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

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

相关文章

视频行人搜索 (Person Search in Videos)

文章目录 视频行人搜索 (Person Search in Videos)图像行人搜索存在问题Video PS 定义MTA-PS数据集First person search dataset in videosComplicated ambient conditions and realistic monitoring scenariosPrivacy insensitivity 方法 视频行人搜索 (Person Search in Vide…

FiRa标准UWB MAC实现(三)——距离如何获得?

继续前期FiRa MAC相关介绍,将FiRa UWB MAC层相关细节进一步进行剖析,介绍了UWB技术中最重要的一个点,高精度的距离是怎么获得的,具体使用的测距方法都有哪些,原理又是什么。为后续FiRa UWB MAC的实现进行铺垫。 3、测距方法 3.1 SS-TWR SS-TWR为Single-Sided Two-Way Ra…

ER实体关系图(一)

用户表(user)、用户钱包表(user_wallet)(与user是1对1关系)、用户钱包交易日志表(user_wallet_log)(与user是1对多关系) user&#xff1a;用户表通常包含用户的基本信息&#xff0c;例如用户ID&#xff08;主键&#xff09;、用户名、密码&#xff08;通常加密存储&#xff09;…

Windows远程桌面连接

试验&#xff1a;使用Oracle VM VirtualBox创建虚拟机与物理机进行远程桌面连接实验 1. 准备 使用VirtualBox创建一台win10虚拟机&#xff0c;并与本地物理机相互ping通。&#xff08;注意&#xff1a;如何存在ping不通&#xff0c;可以试一下关闭Windows的防火墙&#xff09;…

iLogtail 2.0 重大升级,端上支持 SPL

作者&#xff1a;太业 流式处理语言发展 早期流式处理概念&#xff1a; 20 世纪 70 年代&#xff0c;编程语言如 APL 提供了对数组的流式操作&#xff0c;这可以看作是流式处理语法的早期形式。管道&#xff08;Pipes&#xff09;概念在 UNIX 系统中的引进使得可以通过命令行将…

课时152:项目发布_手工发布_方案解读

1.2.1 方案解读 学习目标 这一节&#xff0c;我们从 基础知识、简单实践、小结 三个方面来学习 基础知识 案例需求 实现一套业务环境的项目发布流程&#xff0c;基本的网站架构效果如下&#xff1a;架构解读&#xff1a;负载均衡采用Nginx服务&#xff0c;基于请求内容进行…

孩子用的灯什么样的好?劣质LED台灯所带来的三大危害

随着科技设备不断的进步&#xff0c;护眼台灯已经逐渐成为了书房中不可或缺的一员。它以多功能的特性赢得了广大消费者的青睐。然而&#xff0c;市面上的护眼台灯质量良莠不齐&#xff0c;这使得消费者的选择变得更加困难。不良产品不仅可能带来安全隐患&#xff0c;甚至有潜在…

AI 大模型训练中,通常会采用哪些方法?(输入篇)

大家好 某种程度来说大模型训练的核心算法就是300到400行代码&#xff0c;如果真正理解了并不难。下面我将带大家分析常规大模型训练有几个阶段以及在训练中一般会用到哪些方法。 由上图可以看出&#xff0c;大模型训练主要有四个阶段&#xff1a;预训练、有监督微调、奖励建模…

大模型的高考数学成绩单:及格已经非常好了

让考生头皮发麻的高考数学&#xff0c;可难倒了顶尖 AI 大模型。 一年一度的高考即将落幕&#xff0c;衷心希望各位考生都超常发挥&#xff0c;考出满意的好成绩&#xff01;&#xff01; 和往年一样&#xff0c;除了让 AI 大模型写写高考作文&#xff0c;我们也选取了六家国…

打工人和学生党的福利,NewspaceGpt使用新体验

使用地址&#xff1a;https://newspace.ai0.cn/ 个人名片 &#x1f393;作者简介&#xff1a;java领域优质创作者 &#x1f310;个人主页&#xff1a;码农阿豪 &#x1f4de;工作室&#xff1a;新空间代码工作室&#xff08;提供各种软件服务&#xff09; &#x1f48c;个人邮…

小型气象站:现代气象监测的便携化解决方案

TH-QC12在气象监测领域&#xff0c;技术的不断创新和进步推动了监测设备的多样化和便携化。小型气象站作为这一趋势下的产物&#xff0c;以其体积小、功能全、操作简便等特点&#xff0c;受到了广泛的关注和应用。 小型气象站的技术特点 小型气象站集成了多种气象传感器&…

提升易用性,OceanBase生态管控产品的“从小到大”

2022年&#xff0c;OceanBase发布4.0版本“小鱼”&#xff0c;并首次公开提出了单机分布式一体化这一理念&#xff0c;旨在适应大小不同规模的工作负载&#xff0c;全面满足用户数据库“从小到大”全生命周期的需求。当时&#xff0c;我们所说的“从小到大”主要聚焦于数据库的…

【Qt 学习笔记】Qt窗口 | 对话框 | 模态与非模态对话框的创建

博客主页&#xff1a;Duck Bro 博客主页系列专栏&#xff1a;Qt 专栏关注博主&#xff0c;后期持续更新系列文章如果有错误感谢请大家批评指出&#xff0c;及时修改感谢大家点赞&#x1f44d;收藏⭐评论✍ Qt窗口 | 对话框 | 创建模态及非模态对话框 文章编号&#xff1a;Qt 学…

准橙人工翻译微信小程序,100+专业领域的译者在线帮你翻译!藏语、维吾尔语、哈萨克语、壮语、彝文、蒙古语统统支持人工翻译!

亲爱的朋友们&#xff0c;我们深知每一种语言都承载着独特的文化和历史&#xff0c;为了传承和弘扬这些宝贵的文化遗产&#xff0c;我们诚挚地邀请具备翻译经验并熟练掌握以下任意一门语言的您加入我们的团队&#xff01; 中国少数民族语言&#xff1a;藏语、维吾尔语、哈萨克…

懵了!伦敦银是现货白银吗?

近期&#xff0c;伦敦银价格出现了比较强势的上涨&#xff0c;很多朋友想入场炒银。不过当他们接触伦敦银交易市场的时候就懵了&#xff0c;这个交易品种好像有很多名称&#xff0c;一会儿说伦敦银&#xff0c;一会儿说现货白银&#xff0c;搞得自己都混乱了。到底伦敦银是现货…

CVE-2023-37569(未授权任意文件上传+弱口令爆破)

靶场简介 Online Piggery Management System v1.0 - 存在未授权的文件上传漏洞&#xff0c;登陆界面弱口令爆破 进入靶场 猜测弱口令admin/admin&#xff0c;错误&#xff0c;进行账号密码爆破 得到账号密码 admin/password 登陆进入&#xff0c;找到一处文件上传位置 上传…

千问Qwen7B chat:本地部署及网页端使用

基于前面的安装经验&#xff0c;千问大模型的本地部署并不算难&#xff0c;主要时间用在大模型文件的下载上。同时系统运行对硬件也有较高的要求&#xff0c;本机的硬件配置为N卡3060&#xff0c;显存12G。 使用conda创建虚拟环境&#xff0c;主要版本如下&#xff1a; Pyth…

生成式人工智能 - stable diffusion web-ui安装教程

一、Stable Diffusion WEB UI 屌丝劲发作了,所以本地调试了Stable Diffusion之后,就去看了一下Stable Diffusion WEB UI,网络上各种打包套件什么的好像很火。国内的也就这个层次了,老外搞创新,国内跟着屁股后面搞搞应用层,就叫大神了。 不扯闲篇了,我们这里从git源码直接…

Vue18-列表渲染

一、v-for渲染列表 1-1、遍历数组&#xff08;用的多&#xff09; 1-2、key属性 让每一个<li>都有一个唯一的标识&#xff01; 1、写法一 只有用了遍历的方式(v-for)来生成多个同样结构的数据&#xff0c;必须给每个结构取一个唯一的标识。 2、写法二 或者&#xff1a;…

【全开源】生产管理系统源码(FastAdmin+ThinkPHP+Layui+uniapp)

&#x1f525;揭秘高效生产管理系统&#xff0c;让你的企业腾飞&#xff01;&#x1f680; 一款基于FastAdminThinkPHPLayuiuniapp开发的生产管理系统&#xff0c;帮助企业数字化转型&#xff0c;打造智能工厂&#xff0c;专业为生产企业量身开发的一套完整的生产管理系统。主…