【数据结构】二叉树知识点详解

树的概念

  • 树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合
  • 有一个特殊的结点,称为根结点,根节点没有前驱结点
  • 除根节点外,其余结点被分成M(M>0)个互不相交的集合T1、T2、……、Tm,其中每一个集合Ti(1<= i<= m)又是一棵结构与树类似的子树

image.png
注意:树形结构中,子树之间不能有交集,否则就不是树形结构

树的相关概念

image.png

  • 节点的度:一个节点含有的子树的个数称为该节点的度;
  • 如上图:A的为6叶节点或终端节点**,度为0的节点称为叶节点**;
  • 如上图:B、C、H、I…等节点为叶节点非终端节点或分支节点:度不为0的节点
  • 如上图:D、E、F、G…等节点为分支节点双亲节点或父节点:若一个节点含有子节点,则这个节点称为其子节点的父节点;
  • 如上图:A是B的父节点孩子节点或子节点:一个节点含有的子树的根节点称为该节点的子节点;
  • 如上图:B是A的孩子节点兄弟节点:具有相同父节点的节点互称为兄弟节点;
  • 如上图:B、C是兄弟节点树的度:一棵树中,最大的节点的度称为树的度;
  • 如上图:树的度为6节点的层次:从根开始定义起,根为第1层,根的子节点为第2层,以此类推树的高度或深度:树中节点的最大层次;
  • 如上图:树的高度为4堂兄弟节点:双亲在同一层的节点互为堂兄弟;
  • 如上图:H、I互为兄弟节点节点的祖先:从根到该节点所经分支上的所有节点;
  • 如上图:A是所有节点的祖先子孙:以某节点为根的子树中任一节点都称为该节点的子孙。
  • 如上图:所有节点都是A的子孙森林:由m(m>0)棵互不相交的树的集合称为森林

二叉树概念及结构

概念

image.png
一棵二叉树是结点的一个有限集合,该集合:

  1. 或者为空
  2. 由一个根节点加上两棵别称为左子树和右子树的二叉树组成
  3. 二叉树不存在度大于2的结点
  4. 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树
二叉树的状态

image.png

特殊的二叉树

image.png

  • 满二叉树:一个二叉树,如果每一个层的结点数都达到最大值,则这个二叉树就是满二叉树。也就是说,如果一个二叉树的层数为K,且结点总数是,则它就是满二叉树
  • 完全二叉树:对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从1至n的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树
二叉树的性质
  • 规定根节点的层数为1,则一棵非空二叉树的第i层上最多有2(i-1) 个结点
  • 若规定根节点的层数为1,则深度为h的二叉树的最大结点数是2的h次方- 1
  • 对任何一棵二叉树,如果度为0其叶结点个数为 n1,度为2的分支结点个数为 n2,则有n1=n2+1
  • 若规定根节点的层数为1,具有n个结点的满二叉树的深度,h=log2(n+1)–(ps:log2(n + 1)是log以2为底n+1为对数)
  • 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的数组顺序对所有节点从0开始编号,则对于席号为i的结点有:

关系位置

  1. 若i>0,i位置节点的双亲序号:(i-1)/2;i=0,i为根节点编号,无双亲节点
  2. 若2i+1=n否则无左孩子
  3. 若2i+2=n否则无右孩子

二叉树的存储结构

顺序存储
  • 顺序结构存储就是使用数组来存储,一般使用数组只适合表示完全二叉树,因为不是完全二叉树会有空间的浪费。
  • 而现实中使用中只有堆才会使用数组来存储,二叉树顺序存储在物理上是一个数组,在逻辑上是一颗二叉树。

image.png

链式存储

二叉树的链式存储结构是指,用链表来表示一棵二叉树,即用链来指示元素的逻辑关系。 通常的方法是链表中每个结点由三个域组成,数据域和左右指针域,左右指针分别用来给出该结点左孩子和右孩子所在的链结点的存储地址 。
image.png

遍历过程

先序遍历

image.png

非递归遍历
class Solution {
public:
    void inorder(TreeNode*root,vector<int>&v)
    {
        if(root==nullptr)return;
        
        v.push_back(root->val);
        inorder(root->left,v);
        inorder(root->right,v);
        
        

    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int>v;
        if(!root)return v;
        inorder(root,v);

    return v;
    }
};
非递归遍历(栈)
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int >v;
        stack<TreeNode*>st;
        TreeNode*cur=root; //拷贝一个节点 避免把根节点给删除

        while(cur || !st.empty()) //判断栈是否为空,节点是否为空
        {
            while(cur) //先遍历到最左节点 把节点都压栈
            {
                st.push(cur);
                cur=cur->left;
            }
            TreeNode*top=st.top(); //取栈顶的节点
            v.push_back(top->val);//取值到vtor
            st.pop();//删除栈中的节点
            cur=top->right;//然后就遍历右节点
        }
        return v;
    }
};
中序遍历

image.png

递归遍历
class Solution {
public:
    void inorder(TreeNode*root,vector<int>&v)
    {
        if(root==nullptr)return;
        
        
        inorder(root->left,v);
        v.push_back(root->val);
        inorder(root->right,v);

    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int>v;
        if(!root)return v;
        inorder(root,v);

    return v;
    }
};
非递归遍历(栈)
class Solution {
public:
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int >v;
        stack<TreeNode*>st;
        TreeNode*cur=root; //拷贝一个节点 避免把根节点给删除

        while(cur || !st.empty()) //判断栈是否为空,节点是否为空
        {
            while(cur) //先遍历到最左节点 把节点都压栈
            {
                st.push(cur);
                cur=cur->left;
            }
            TreeNode*top=st.top(); //取栈顶的节点
            v.push_back(top->val);//取值到vtor
            st.pop();//删除栈中的节点
            cur=top->right;//然后就遍历右节点
        }
        return v;
    }
};
后序遍历

image.png

递归遍历
class Solution {
public:
    void inorder(TreeNode*root,vector<int>&v)
    {
        if(root==nullptr)return;
        
        
        inorder(root->left,v);
        inorder(root->right,v);
        v.push_back(root->val);
        
    }
    vector<int> inorderTraversal(TreeNode* root) {
        vector<int>v;
        if(!root)return v;
        inorder(root,v);

    return v;
    }
};
非递归遍历(栈)
class Solution {
public:
    vector<int> postorderTraversal(TreeNode* root) {
        stack<TreeNode* >st; 
        vector<int>v;
        TreeNode*cur=root;    //拷贝节点
        TreeNode*prev=nullptr;    

        while(cur||!st.empty())  
        {
            while(cur)   //存储根到最左的所有节点
            {
                st.push(cur);
                cur=cur->left;
            }

           TreeNode*top=st.top();      //记录最左节点

            //如果他的右是空那么他的左右都没有子节点了,这时就可以进数据 ;
            //top->right==prev 这里保证了右节点的插入数据,记录上一个经过的节点
            if(top->right==nullptr||top->right==prev)    
            {
                v.push_back(top->val);
                st.pop();
                prev=top;                   //记录上一个节点
            }
            else
            {
                cur=top->right;      
            }
        }
    return v;
    }
};
层次遍历

image.png

非递归遍历(队列)
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        
        //层序遍历   同深度的一个集合
        vector<vector<int>> v; //存放每一层的数据
        if(!root)
        {
            return v;
        }
        queue<TreeNode*> q; 
        q.push(root);

        while(!q.empty())//这里一直不为空
        {   
            int ret=q.size();//计算当前层的节点个数
            vector<int>cur;
            while(ret--)
            {
                TreeNode*node =q.front();//头部为左节点
                q.pop();
                cur.push_back(node->val);//取节点值
                if(node->left) 
                    q.push(node->left); //取左节点
                if(node->right) 
                    q.push(node->right);//取右节点
            }
            v.push_back(cur);
        }
        return v;
    }
};
方法2
class Solution {
public:
    vector<vector<int>> levelOrder(TreeNode* root) {
        
        queue <TreeNode*>q;
        int size=0;
        if(root)
        {
            q.push(root);
            size=1;
        }
        
    vector<vector<int>> vv;
    while(!q.empty())
    {
        vector<int>v;
        while(size--) //每一层的个数
        {
            TreeNode* t=q.front();
            q.pop();
            v.push_back(t->val);

            if(t->left)
                q.push(t->left);
            if(t->right)
                q.push(t->right);
        }
        vv.push_back(v);
        size=q.size();//更新
    }
    return vv;
    }
};

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

STM32-DAC

DAC 前言一、理论介绍二、DAC代码三、实验结果总结 前言 前言写个参考吧 STM32 DAC串口 一、理论介绍 DAC是数字模拟转换器&#xff08;Digital to Analog Converter&#xff09;的缩写&#xff0c;它是一种将数字信号转换为模拟信号的设备。 RC有2个通道。 DAC的初始化 #…

Vue3专栏项目 -- 一、第一个页面(上)

一、ColumnList 组件&#xff08;专栏列表组件&#xff09;编码&#xff1a; 该组件要接收一个数组&#xff0c;数组中是一个个专栏数据&#xff0c;数据中包括id、title、avator、description。所以我们定义一个泛型&#xff0c;泛型为id为number类型title为string类型如下这…

【从零开始学架构 架构基础】架构设计的本质、历史背景和目的

本文是《从零开始学架构》的第一篇学习笔记&#xff0c;主要理解架构的设计的本质定义、历史背景以及目的。 架构设计的本质 分别从三组概念的区别来理解架构设计。 系统与子系统 什么是系统&#xff0c;系统泛指由一群有关联的个体组成&#xff0c;根据某种规则运作&#…

VS Code安装通义灵码插件

搜索通义灵码插件 当编写完部分代码后&#xff0c;会出现通义灵码的图标&#xff0c;点击该图标&#xff0c;可以选择补全代码。 之后需要登录阿里云账号 返回vscode 在左下角输入框输入提出的问题“合并两个数组”&#xff0c;回车显示问题的答案。

简单了解泛型

基本数据类型和对应的包装类 在Java中, 基本数据类型不是继承自Object, 为了在泛型代码中可以支持基本类型, Java给每个基本类型都对应了一个包装类型. 简单来说就是让基本数据类型也能面向对象.基本数据类型可以使用很多方法, 这就必须让它变成类. 基本数据类型对定的包装类…

免费思维13招之一:体验型思维

思维01:体验型思维 第一大战略:体验型思维。 体验型思维是免费思维中最简单的思维,我们先从最简单的讲起,由简入繁,简单的我们少讲,复杂的我们多讲。 那么,什么是体验型思维呢? 很简单,就是先让客户进行体验,再进行成交的方式。这一种思维,具体的可以分为两种:…

yolo world 瑞芯微芯片rknn部署、地平线芯片Horizon部署、TensorRT部署

特别说明&#xff1a;参考官方开源的 yoloworld 代码、瑞芯微官方文档、地平线的官方文档&#xff0c;如有侵权告知删&#xff0c;谢谢。 模型和完整仿真测试代码&#xff0c;放在github上参考链接 模型和代码。 yoloworld出来的有一段时间了&#xff0c;还没有盘到板端上玩一玩…

IJCAI 2024:吉林大学、中国科学院计算技术研究所和自动化研究所等揭示数据增强在开放场景下的“两面性”

吉林大学人工智能学院研究员高一星、中国科学院计算技术研究所副研究员唐帆、中国科学院自动化研究所研究员董未名等在人工智能领域的CCF-A类顶级国际会议IJCAI上发表的工作&#xff0c;揭示并分析基于样本混合的数据增强方法在开放场景下存在的问题&#xff0c;提出了基于非对…

《安富莱嵌入式周报》第336期:开源计算器,交流欧姆表,高性能开源BLDC控制器,Matlab2024a,操作系统漏洞排名,微软开源MS-DOS V4.0

周报汇总地址&#xff1a;嵌入式周报 - uCOS & uCGUI & emWin & embOS & TouchGFX & ThreadX - 硬汉嵌入式论坛 - Powered by Discuz! 本周更新一期视频教程&#xff1a; BSP视频教程第30期&#xff1a;UDS ISO14229统一诊断服务CAN总线专题&#xff0c;常…

C++:多态-虚函数

C 中的多态性是面向对象编程中的一个重要概念&#xff0c;它允许在运行时选择不同的函数实现&#xff0c;以适应不同类型的对象。 多态的种类 编译时多态性&#xff08;Compile-time Polymorphism&#xff09;&#xff1a;也称为静态多态性或早期绑定&#xff0c;指在编译时确…

java.lang.Exception: Test class should have exactly one public zero-

1.原因 Test方法所在类中,不能存在有参数构造函数,无参构造可以存在。JUnit在运行测试之前&#xff0c;会对测试类做一些初始化和验证工作。对于普通的非参数化测试&#xff0c;JUnit期望测试类有一个无参的公共构造函数&#xff0c;这样它才能够实例化测试类并执行其中的测试方…

K8S快速入门

K8S快速入门 在学习k8s的过程&#xff0c;虽然官网给出的示例教程很简单&#xff0c;但是由于网络和环境的差异&#xff0c;导致实际操作的时候踩了很多坑&#xff0c;下面记录一下自己的操作步骤&#xff0c;方便需要的人参考&#xff0c;也方便以后的自己。 参考官网的资料…

uni-app+vue3 +uni.connectSocket 使用websocket

前言 最近在uni-appvue3websocket实现聊天功能&#xff0c;在使用websocket还是遇到很多问题 这次因为是app手机应用&#xff0c;就没有使用websocket对象&#xff0c;使用的是uni-app的uni.connectSocket 为了方便测试这次用的是node.js一个简单的dom&#xff0c;来联调模拟…

五分钟解决Springboot整合Mybaties

SpringBoot整合Mybaties 创建maven工程整合mybaties逆向代码生成 创建maven工程 1.通过idea创建maven工程如下图 2.生成的工程如下 以上我们就完成了一个maven工程&#xff0c;接下来我们改造成springboot项目。 这里主要分为三步&#xff1a;添加依赖&#xff0c;增加配置&…

Spring_概述

Spring 官网Spring Framework&#xff08;Spring&#xff09;文档位置重点内容Overview 官网 Spring官网 Spring Framework&#xff08;Spring&#xff09; 文档位置 重点 IoC容器AOP&#xff1a;面向切面编程AOT&#xff1a;ahead of time&#xff0c;提前编译Web 框架&…

20240507 ubuntu20.04+ros noetic 跑通lioslam

任务&#xff1a;跑通lioslam 主要参考博客 IMU激光雷达融合使用LIO-SAM建图学习笔记——详细、长文、多图、全流程_ubuntu_AIDE回归线-GitCode 开源社区 (csdn.net) 1.不要用这一句 wget -O ~/Downloads/gtsam.zip https://github.com/borglab/gtsam/archive/4.0.0-alpha2…

电商大数据的采集||电商大数据关键技术【基于Python】

.电商大数据采集API 什么是大数据&#xff1f; 1.大数据的概念 大数据即字面意思&#xff0c;大量数据。那么这个数据量大到多少才算大数据喃&#xff1f;通常&#xff0c;当数据量达到TB乃至PB级别时&#xff0c;传统的关系型数据库在处理能力、存储效率或查询性能上可能会遇…

Mac idea gradle解决异常: SSL peer shut down incorrectly

系统&#xff1a;mac 软件&#xff1a;idea 解决异常: SSL peer shut down incorrectly 查看有没有安装 gradle -v安装 根据项目gradle提示安装版本 brew install gradle7idea的配置 在settings搜索gradle&#xff0c;配置Local installation&#xff0c;选择自己的安装目录…

c++编程(10)——string

欢迎来到博主的专栏——c编程 博主ID&#xff1a;代码小豪 文章目录 <string>string类的接口构造、析构、与赋值重载构造函数赋值重载运算符 元素访问operator[] 容量修改器对string对象的操作迭代器 std::string是定义在c标准的一个类&#xff0c;定义在标准库<strin…

【SAP ME 34】POD操作面板打开内部异常500内部异常

解决方案&#xff1a; 切换到configtool目录&#xff0c;打开configtool可执行文件