数据结构和算法之树形结构(1)

文章出处: 数据结构和算法之树形结构(1)  关注码农爱刷题,看更多技术文章!!

        树形结构是数据结构四种逻辑结构之一,也是被广泛使用的一种逻辑结构,它描述的是数据元素之间一对多的逻辑关系。树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合;它有一个起始节点,称之为根节点;从根节点往下逐层延伸,每个节点都可以有零个或多个子节点,有且只有一个父节点,根节点无父节点,形体像一棵倒挂的树,因而被称之为树形结构。 树形结构逻辑上有序的意思,就是从根节点往下延伸的顺序,因而和线性结构一样是有序结构。

       树形结构常用于表示具有层次关系的数据,例如文件系统、组织结构、目录结构等。它提供了一种便捷的方式来组织和访问数据。树形结构的应用非常广泛,例如在计算机科学中,树型结构被用于实现搜索算法(如二叉搜索树)、存储和检索数据(如B树、堆)、表达抽象语法树等。在现实生活中,树型结构也有很多应用,比如家谱、图书分类、产品组织关系等。

 一、基本概念

图片

 二、二叉树
      二叉树的定义

      二叉树是典型和常见的树形结构,也是最简单的树形结构。二叉树每个节点最多有两棵子树(二叉树中不存在度大于2的节点),并且二叉树的子树有左右之分,顺序不能颠倒。

     二叉树根据样式不同,还可以分为满二叉树和完全二叉树,例如下图:

图片

     若一棵树的层数为k,它总结点数是2^k-1,则这棵树就是满二叉树。上图编号2的树就是一棵满二叉树,该树4层节点数15 = 2^4-1;满二叉树的特点是叶子节点都在最底层,除了叶子节点,每个节点都有左右两个子节点。

      若一棵树的层数为k,它前k-1层的总结点数是2^(k-1)-1,第k层的结点按照从左往右的顺序排列,则这棵树就是完全二叉树。上图编号3的树就是一棵完全二叉树,该树4层前3层节点数7 = 2^(4-1)-1;完全二叉树的特点是:叶子节点都在最底下两层,最后一层的叶子节点都靠左排列,并且除了最后一层,其他层的节点个数都要达到最大值2。看下图识别完全二叉树和非完全二叉树的区别。

图片

      此外, 满二叉树一定是一棵完全二叉树,但完全二叉树不一定是满二叉树。 

      二叉树的存储结构

      二叉树在实际落地时,可以采用顺序存储结构和链式存储结构,关于两者的区别可以参看前面的文章数据结构和算法之基本概念。如果是采用链式存储结构,一个节点分为三部分,其中数据域存储数据,另外两个指针域,一个指向左边的子节点,一个指向右边的子节点,这是一个典型的链表结构(关于链表结构说明可以参看文章数据结构和算法之线性结构)。通常,这是二叉树常用的存储结构。

      如果采用顺序存储结构,通常是采用数组来实现。那数组是如何存储二叉树节点数据的呢?  其存储规则是:从根节点开始,逐层往下、从左至右依次存储,看下图能更形象地理解其存储规则:

图片

       从上图可以看出:如果节点 X 存储在数组中下标为 i 的位置,下标为 2 * i 的位置存储的就是左子节点,下标为 2 * i + 1 的位置存储的就是右子节点;反过来,下标为 i/2 的位置存储就是它的父节点。通过这种方式,我们只要知道根节点存储的位置(一般情况下,为了方便计算子节点,根节点会存储在下标为1的位置),这样就可以通过下标计算,把整棵树都串起来。

       二叉树的遍历

        二叉树的遍历通常有两种搜索遍历方法:深度优先遍历广度优先遍历。深度优先遍历(Depth-First Search,简称DFS)即优先深入地探索一个节点的某一条路径,直到该路径都已被探索完,然后再回溯到该节点,探索该节点另一条路径,以此类推;广度优先遍历(Breadth-First Search,简称BFS)则是同时对所有路径逐层进行探索。

      深度优先遍历根据遍历的顺序不同,又可以细分为三种不同的遍历顺序:前序遍历、中序遍历、后序遍历。三种遍历顺序定义如下:

图片

      无论哪种遍历顺序,左节点都要优先右节点遍历, 三种遍历顺序实际遍历结果以下图为例:

图片

       前序遍历结果是:ABDHIEJCFG; 中序遍历结果是:HDIBJEAFCG;后序遍历结果是:HIDJEBFGCA。代码层面,通常我们可以通过递归实现前述深度优先遍历的三种遍历顺序,代码如下:

public class Solution { private static class Node { public int data;  // 节点值public Node left;  // 左节点  public Node right;  // 右节点public Node(int data, Node left, Node right) { this.data = data; this.left = left; this.right = right; } } public static void preDfs(Node treeNode) { if (treeNode == null) { return; } System.out.println(treeNode.data);  // 访问节点本身preDfs(treeNode.left);  // 遍历左节点preDfs(treeNode.right);  // 遍历右节点} public static void middleDfs(Node treeNode) { if (treeNode == null) { return; }        middleDfs(treeNode.left);  // 遍历左节点System.out.println(treeNode.data);  // 访问节点本身middleDfs(treeNode.right);  // 遍历右节点} public static void lastDfs(Node treeNode) { if (treeNode == null) { return; }        lastDfs(treeNode.left);  // 遍历左节点      lastDfs(treeNode.right);  // 遍历右节点System.out.println(treeNode.data);  // 访问节点本身} 
}

       如果是广度优先遍历,上面二叉树图遍历的结果则是:ABCDEFGHIJ;广度优先遍历符合队列先进先出的特点,实现时可以考虑用队列,如下面代码:


public static void bfs(Node root) {if (root == null) {return;}LinkedList<Node> queue = new LinkedList<Node>();Node current = null;// 根节点入队queue.offer(root);// 左侧数的深度int leftNum = 0;// 右侧数的深度int rightNum = 0;// 只要队列中有元素,就可以一直执行,非常巧妙地利用了队列的特性while (!queue.isEmpty()) {// 出队队头元素 先进先出current = queue.poll();System.out.print("-->" + current.data);// 左子树不为空,入队if (current.left != null) {queue.offer(current.left);leftNum++;}// 右子树不为空,入队if (current.right != null) {queue.offer(current.right);rightNum++;}}System.out.println(rightNum + "\t" + leftNum);
}

       上述代码中Node类的定义与之前代码里的Node类一致。代码逻辑分析:先是根节点入队,第一次循环,根节点出队(第一层),然后是第二层左右节点入队;第二次循环,左节点出队,左节点左右两孙节点入队;第三次循环,右节出队,右节点左右两孙节点入队,至此二层节点全部出队;第四次循环,左节点左孙节点出队,其左右子节点再入队,以此类推。

       深度广度优先遍历和广度优先遍历不仅仅用于二叉树的遍历,事实上,两者是两种基本且重要的图与树的遍历算法,它们的应用场景和优缺点如下图表:

图片

       本章主要介绍了树形结构的基本概念和特点,以及二叉树的定义、存储结构和遍历算法,关于树形结构的深入知识将在后续文章继续介绍,烦请关注!!    

码农爱刷题

为计算机编程爱好者和从业人士提供技术总结和分享 !为前行者蓄力,为后来者探路!

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

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

相关文章

初识模版!!

初识模版 1.泛型编程1.1 如何实现一个交换函数呢&#xff08;使得所有数据都可以交换&#xff09;&#xff1f;1.2 那可以不可以让编译器根据不同的类型利用该模子来生成代码呢&#xff1f; 2.模版类型2.1 模版概念2.2 函数模版的原理2.3 函数模板的实例化2.4 模板参数的匹配原…

如何优化前端页面的 AJAX 请求性能并避免冲突

个人名片 🎓作者简介:java领域优质创作者 🌐个人主页:码农阿豪 📞工作室:新空间代码工作室(提供各种软件服务) 💌个人邮箱:[2435024119@qq.com] 📱个人微信:15279484656 🌐个人导航网站:www.forff.top 💡座右铭:总有人要赢。为什么不能是我呢? 专栏导…

开源 AI 智能名片 S2B2C 商城小程序与正能量融入对社群归属感的影响

摘要&#xff1a;本文探讨了开源 AI 智能名片 S2B2C 商城小程序在社群运营中的作用&#xff0c;以及融入正能量对提高社群归属感的关键意义。通过分析正能量的精神感染力和对社群氛围的积极影响&#xff0c;阐述了在开源 AI 智能名片 S2B2C 商城小程序的各类活动中融入正能量的…

flask项目初始化

1、初始环境 python3.8 2、flask文档地址&#xff1a;https://flask.palletsprojects.com/en/latest/installation/#install-flask 3、初始化项目 $ mkdir myproject $ cd myproject $ python3 -m venv .venv $ . .venv/bin/activate $ pip install Flask4、打开项目mypr…

Ansible——Playbook基本功能???

文章目录 一、Ansible Playbook介绍1、Playbook的简单组成1&#xff09;“play”2&#xff09;“task”3&#xff09;“playbook” 2、Playbook与ad-hoc简单对比区别联系 3、YAML文件语法&#xff1a;---以及多个---&#xff1f;&#xff1f;使用 include 指令 1. 基本结构2. 数…

java后端字节一面

1. 我现在和你进行视频通话&#xff0c;这个是怎么做的&#xff1f; 视频通话通常基于实时通信技术&#xff08;RTC&#xff09;&#xff0c;如WebRTC。它利用现代浏览器的API来实现视频、音频和数据的直接P2P&#xff08;点对点&#xff09;通信&#xff0c;或通过服务器中转。…

【JavaEE】IP协议 应用层协议

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【Java】登神长阶 史诗般的Java成神之路 &#x1f576;️一.IP地址 IP协议&#xff08;Internet Protocol&#xff09;是TCP/IP协议族中最核心的协议之一&#xff0c;它定义了数据包在网络中传输的标准…

应用层协议HTTP介绍

一、HTTP协议介绍 HTTP&#xff08;HyperText Transfer Protocol&#xff0c;超文本传输协议&#xff09;是一个至关重要的协议。它定义了客户端&#xff08;如浏览器&#xff09;与服务器之间如何通信&#xff0c;以交换或传输超文本。 超文本&#xff1a;视频&#xff0c;音…

24年蓝桥杯及攻防世界赛题-MISC-1

2 What-is-this AZADI TOWER 3 Avatar 题目 一个恐怖份子上传了这张照片到社交网络。里面藏了什么信息?隐藏内容即flag 解题 ┌──(holyeyes㉿kali2023)-[~/Misc/tool-misc/outguess] └─$ outguess -r 035bfaa85410429495786d8ea6ecd296.jpg flag1.txt Reading 035bf…

如何使用命令行快速下载Google Drive/OneDrive大文件

OneDrive OneDrive使用wget下载会出现403 forbidden&#xff0c;可通过下面方法下载。 浏览器右键进入检查界面&#xff0c;选择netowork&#xff0c;搜索download.aspx&#xff0c;然后在待下载文件处点击下载&#xff0c;即可出现下载链接&#xff0c;复制为cURL即可下载。…

日志收集工具 Fluentd vs Fluent Bit 的区别

参考链接&#xff1a; FluentdFluentd BitFluentd & Fluent Bit | Fluent Bit: Official Manual Fluentd 与 Fluent Bit 两者都是生产级遥测生态系统&#xff01; 遥测数据处理可能很复杂&#xff0c;尤其是在大规模处理时。这就是创建 Fluentd 的原因。 Fluentd 不仅仅是…

jenkins声明式流水线语法详解

最基本的语法包含 pipeline&#xff1a;所有有效的声明式流水线必须包含在一个 pipeline 块中stages&#xff1a;包含一系列一个或多个stage指令stage&#xff1a;stage包含在stages中进行&#xff0c;比如某个阶段steps&#xff1a;在阶段中具体得执行操作&#xff0c;一个或…

React js Router 路由 2, (把写过的几个 app 组合起来)

完整的项目&#xff0c;我已经上传了&#xff0c;资源链接. 起因&#xff0c; 目的: 每次都是新建一个 react 项目&#xff0c;有点繁琐。 刚刚学了路由&#xff0c;不如写一个 大一点的 app &#xff0c;把前面写过的几个 app, 都包含进去。 这部分感觉就像是&#xff0c; …

[ IDE ] SEGGER Embedded Studio for RISC-V

一、FILE 二、Edit 三、View 四、Search 五、Navigate 六、Project 七、Build 7.1 编译 先选择一个目标类型&#xff0c;再选择编译。 八、Debug 九、Target 十、Tools 10.1 自定义快捷键 点击菜单项&#xff0c;通过Tools –> Options –> Keyboard&#xff0c;实现自…

Java | Leetcode Java题解之第413题等差数列划分

题目&#xff1a; 题解&#xff1a; class Solution {public int numberOfArithmeticSlices(int[] nums) {int n nums.length;if (n 1) {return 0;}int d nums[0] - nums[1], t 0;int ans 0;// 因为等差数列的长度至少为 3&#xff0c;所以可以从 i2 开始枚举for (int i …

安卓13设置动态显示隐藏第一页的某一项 动态显示隐藏无障碍 android13设置动态显示隐藏第一页的某一项

总纲 android13 rom 开发总纲说明 文章目录 1.前言2.问题分析3.代码分析4.代码修改4.1修改方法14.2修改方法25.编译6.彩蛋1.前言 有时候,我们的设置里面显示的信息,需要根据不同的情况显示不同的信息,例如,动态的显示或者隐藏 “无障碍” 这一项。 2.问题分析 像这个问题…

英集芯IP5902:集成电压可调异步升压转换充电管理功能的8位MCU芯片

英集芯IP5902是一款集成了9V异步升压转换、锂电池充电管理及负端NMOS管的8-bit MCU芯片&#xff0c;外壳采用了SOP16封装形式&#xff0c;高集成度和丰富的功能使其在应用时只需很少的外围器件&#xff0c;就能有效减小整体方案的尺寸&#xff0c;降低BOM成本&#xff0c;为小型…

Day69补 前后端分离思想

ajax前后端分离 前后端分离处理&#xff1a;前端------&#xff08;数据&#xff09;-----服务端----&#xff08;数据&#xff09;-----前端-----动态改变页面的内容 1.json 1、JSON&#xff1a;由于JSON易读以及纯文本格式的特性&#xff0c;可以非常容易地与其他程序进行沟通…

业务安全治理

业务安全治理 1.账号安全撞库账户盗用 2.爬虫与反爬虫3.API网关防护4.钓鱼与反制钓鱼发现钓鱼处置 5.大数据风控风控介绍 1.账号安全 撞库 撞库分为垂直撞库和水平撞库两种&#xff0c;垂直撞库是对一个账号使用多个不同的密码进行尝试&#xff0c;可以理解为暴力破解&#x…

MVCC机制解析:提升数据库并发性能的关键

MVCC机制解析&#xff1a;提升数据库并发性能的关键 MVCC&#xff08;Multi-Version Concurrency Control&#xff09; 多版本并发控制 。 MVCC只在事务隔离级别为读已提交(Read Committed)和可重复读(Repeated Read)下生效。 MVCC是做什么用的 MVCC是为了处理 可重复读 和…