数据结构之树型结构

news2024/11/25 14:51:25

    • 相关概念
    • 树的表示
    • 二叉树
      • 二叉树性质
      • 二叉树储存
    • 实现一颗二叉树
      • 创建
      • 遍历(前中后序)
      • 获取树中节点个数
      • 获取叶子节点个数
      • 获取第k层节点个数
      • 获取二叉树高度
      • 检测值为value元素是否存在
      • 层序遍历(需要队列来实现)
      • 判断是否为完全二叉树(需要队列来实现)

相关概念

在这里插入图片描述
重点概念:后续学习将会反反复复出现
在这里插入图片描述

对我们当前学习稍微不重要:

在这里插入图片描述

树的表示

树有很多种表示方式,如:双亲表示法,孩子表示法、孩子双亲表示法(AVL树、红黑树、B树会用到)、孩子兄弟表示法等等。我们了解一下孩子兄弟表示法:
在这里插入图片描述
代码表示:

class Node{
	int value;//我们当前学习就是简简单单的存个int数字
	Node firstChild;
	Node nextNorther;

}

二叉树

二叉树:每一个节点的度小于等于2;其实就是每一个节点的孩子个数不超过两个。二叉树的有次序是指你把右子树放左边画出来,结果就是两个不同的树
任意二叉树都是由以下的情况组合的:
在这里插入图片描述
满二叉树:每层的结点数都达到最大值;如果层数是k;满二叉树的节点个数为2^k-1

完全二叉树:你按左右到上下编号1-n一定是连续的
在这里插入图片描述

二叉树性质

前提:规定第一层是根节点的二叉树
1:第i层最多节点个数:2^(i-1)
2:深度为k;总节点个数最多是2^k-1 (完全二叉树的情况)

3:非常重要;任意的二叉树;叶子节点个数比度为2的节点个数多一个(度为0就是叶子,不涉及到度为1的节点)
n0=n2+1 (如果要把n1也扯上关系;使用n-1=n00+n11+n2*2;n是总节点个数;解释:一颗n个节点的树有N-1条边;而叶子节点不产生边;度为1的节点只产生一条边;度为2的节点产生两条边)
比如有4层:
其实就是;2的4次方等于2的3次方+2都平方+2的1次方+2的0次方+1。
题目:
某二叉树共有399个结点,其中有199个度为2的结点,则该二叉树中的叶子结点数为()
A不存在这样的二叉树
B200
C198
D199

4:具有n个结点的完全二叉树的深度k为log(n+1)向上取整
不受到你最后层节点个数影响,最后层一个跟2的n-1个是一样,因为用最大节点个数推导出来的
5:对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0开始编号,则对于序号为i的结点有:
若i>0,双亲序号:(i-1)/2;i=0,i为根结点编号,无双亲结点若2i+1<n,左孩子序号:2i+1,否则无左孩子
若2i+2<n,右孩子序号:2i+2,否则无右孩子
注意:完全二叉树度为1的节点要么是1个,要么是0个。奇数个节点就没有度为1的节点,偶数个节点就有一个度为1的节点。如果题目告诉你2n个节点;那就说明有度为1的节点

二叉树储存

在这里插入图片描述
如何遍历:
先序:根—>左子树---->右子树(这个比较容易理解)
中序:左子树—>根—>右子树(先访问左子树,然后你左子树又得按照中序进行)
后序:左子树–>右子树—>根

实现一颗二叉树

创建

//创建一颗树
class  tree{
    //树的节点,还是内部类实现,类似链表
    class Listnode{
        //一个节点包含三个域
        char val;
        Listnode left;//左边
        Listnode right;//右边

        public Listnode(char val) {
            this.val = val;
        }
    }
    public Listnode create(){
        //先把节点和值创建好,然后再绑关系
        Listnode A=new Listnode('A');
        Listnode B=new Listnode('B');
        Listnode C=new Listnode('C');
        Listnode D=new Listnode('D');
        Listnode E=new Listnode('E');
        Listnode F=new Listnode('F');
        Listnode G=new Listnode('G');
        //这里的B和C是节点
        A.left=B;
        A.right=C;
        B.left=D;
        B.right=E;
        C.left=F;
        C.right=G;

        return A;//返回根节点
    }

遍历(前中后序)

前序:

   public void print1(Listnode root){
        if(root==null) {
            return ;
        }
        System.out.println(root.val);
        print1(root.left);
        print1(root.right);

    }

中序:这次我们就不打印;遍历把值存在顺序表里

    public List<Character> print2(Listnode root){
        List<Character> list=new ArrayList<>();
        if(root==null)
        {
            return list;
        }
        //System.out.println(root.val);
        list.add(root.val);
        print2(root.left);
        print2(root.right);
        return list;
    }

后序:

public List<Character> print3(Listnode root){
    List<Character> ret=new ArrayList<>();
    if(root==null)
    {
        return ret;
    }
    //System.out.println(root.val);
    ret.add(root.val);//先把头放进去,然后左边放一个表,右边放一个表,最后放到ret
    List<Character> s=print3(root.left);
               ret.addAll(s);
    List<Character> s1=print3(root.right);
    ret.addAll(s1);
    return ret;
}

获取树中节点个数

//获取树中节点的个数
    int num=0;
    public int size(Listnode root){
        //遍历计数器
        if(root==null) {
            return 0;
        }
        num++;
        size(root.left);
        size(root.right);
        return num;
    }
    //子问题计数
    public int size1(Listnode root){
        if(root==null) {
            return 0;
        }
        int tmp =size1(root.left)+size1(root.right)+1;//(把走到每个节点都分为左边、右边和它自己)
        return tmp;
    }

获取叶子节点个数

   // 获取叶子节点的个数
    int ret3=0;
     public  void getLeafNodeCount(Listnode root){
//自己为空,肯定就结束了
    if(root==null){
        return ;
    }
    //如果左边和右边同时为空就计数
         if(root.left==null&&root.right==null){
             ret3++;
         }
       getLeafNodeCount(root.left);
       getLeafNodeCount(root.right);

     }
    // 子问题思路-求叶子结点个数
    public  int getLeafNodeCount1(Listnode root){
//自己为空,肯定就结束了
        if(root==null){
            return 0;
        }
        //如果左边和右边同时为空就计数
        if(root.left==null&&root.right==null){
            return 1;
        }
        return getLeafNodeCount1(root.left)+getLeafNodeCount1(root.right);

    }

获取第k层节点个数

   // 获取第K层节点的个数,直接子问题
  public  int getKLevelNodeCount(Listnode root,int k){
//我们之前不是求了一棵树节点个数吗;假设我要求k层,在k-1的左右子树的和
	if(root==null||k<=0) {
	      return -1;
	}
	if(k==1){//这时候条件就不再是root.left==null&&root.right==null;而是k-1层的孩子节点我都要计算
	    return 1;
	}
	int tmp=getKLevelNodeCount(root.left,k-1)+getKLevelNodeCount(root.right,k-1);

	return tmp;
    }



获取二叉树高度

非常巧妙:递归的结束root==null;返回上一级到叶子节点;发现height1>height2不成立;叶子节点的右边+1;如果是root.left遍历下的就返回给这里的值。画个图就好理解

  // 获取二叉树的高度
    public int getHeight(Listnode root) {
        if(root==null){
            return 0;
        }
        int height1=  getHeight(root.left);
        int height2= getHeight(root.right);
        if (height1>height2){
            return height1+1;//加1是关键,每结束一层+1
        }
        else
            return height2+1;
    }

在这里插入图片描述

检测值为value元素是否存在

   // 检测值为value的元素是否存在
   public Listnode find(Listnode root, int val) {
       if (root == null) {
           return null;
       }
       if (root.val == val) {

           return root;
       }
       find(root.left, val);//这里应该把find(root.left,val)存到ret里,避免下面用这个又要重复再递归一次
       if (find(root.left, val).val == val) {
           return root;
       }     //如果我在左边找到就不去右边

       //如果我在右边找到就直接结束,如果都没找到
       find(root.right, val);
       if (find(root.right, val).val == val) {
           return root;
       }
       return null;

       
   }

层序遍历(需要队列来实现)

因为二叉树;没法按这种顺序来遍历;就得依靠别的数据结构
在这里插入图片描述
这样子它的打印顺序就是从左到右;画图分析好
在这里插入图片描述

判断是否为完全二叉树(需要队列来实现)

队列;逻辑:按层次遍历弹出,把Null也放入队列里,当弹出Null的时候发现队列全为Null,就说明是完全二叉树
。不全为null就不是完全二叉树。

   // 判断一棵树是不是完全二叉树   ,这题逻辑还是非常清晰
    public boolean isCompleteTree(TreeNode root) {
        if(root == null) {
            return true;
        }
        Queue<TreeNode> qu = new LinkedList<>();
        qu.offer(root);
        while (!qu.isEmpty()) {
            TreeNode cur = qu.poll();
            if(cur != null) {
                qu.offer(cur.left);
                qu.offer(cur.right);
            }else {
                break;
            }
        }
        //判断队列剩下的值 是否有 非null的数据
        while (!qu.isEmpty()) {
            TreeNode pop = qu.poll();
            if(pop != null) {
                return false;
            }
        }
        return true;
    }

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

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

相关文章

Day48|leetcode 198.打家劫舍、213.打家劫舍II、打家劫舍|||

leetcode 198.打家劫舍 题目链接&#xff1a;198. 打家劫舍 - 力扣&#xff08;LeetCode&#xff09; 视频链接&#xff1a;动态规划&#xff0c;偷不偷这个房间呢&#xff1f;| LeetCode&#xff1a;198.打家劫舍_哔哩哔哩_bilibili 题目概述 你是一个专业的小偷&#xff0c;…

Java实现根据按图搜索商品数据,按图搜索获取1688商品详情数据,1688拍立淘接口,1688API接口封装方法

要通过按图搜索1688的API获取商品详情跨境属性数据&#xff0c;您可以使用1688开放平台提供的接口来实现。以下是一种使用Java编程语言实现的示例&#xff0c;展示如何通过1688开放平台API获取商品详情属性数据接口&#xff1a; 首先&#xff0c;确保您已注册成为1688开放平台…

Android工具条

在底层&#xff0c;所有通过主题得到应用条的活动都使用ActionBar类实现它的应用条。不过最新的应用条特性已经增加到AppCompat支持库中的Toolbar类。这意味着&#xff0c;如果你想在应用中使用最新的应用条特性&#xff0c;就需要使用支持库中的ToolBar类。 如何增加工具条 1…

C++中数组作为参数进行传递方法

文章目录 基础&#xff1a;数组作为函数形参示例&#xff1a;1、一维数组的传递&#xff08;1&#xff09;直接传递&#xff08;2&#xff09;指针传递&#xff08;3&#xff09;引用传递 2、二维数组的传递&#xff08;1&#xff09;直接传递&#xff08;2&#xff09;指针传递…

【产品规划】优先级规划

文章目录 1、功能优先级保障了产品在最短时间接受验证2、隐藏在优先级背后的是产品的目标和价值3、敏捷方法论中的功能优先级制定方法4、优先级制定时常见问题和应对方法5、敏捷方法论中的开发计划制定 1、功能优先级保障了产品在最短时间接受验证 2、隐藏在优先级背后的是产品…

C语言数值表示——进制、数值存储方式

进制 进制也就是进位制&#xff0c;是人们规定的一种进位方法对于任何一种进制—X进制&#xff0c;就表示某一位置上的数运算时是逢X进一位 十进制是逢十进一&#xff0c;十六进制是逢十六进一&#xff0c;二进制就是逢二进一&#xff0c;以此类推&#xff0c;x进制就是逢x进位…

Git基础教程-常用命令整理:学会Git使用方法和错误解决

目录 一、了解Git的基本概念 二、Git的安装和配置 Git的安装 Git的配置 用户信息 文本编辑器 差异分析工具 查看配置信息 三、Git的基本操作 基本原理 基本操作命令 基本操作示例 场景一&#xff1a;创建新仓库 场景二&#xff1a;拉取并编辑远程仓库 四、常见问…

Java“牵手”1688商品跨境属性数据,1688API接口申请指南

1688平台商品详情跨境属性数据接口是开放平台提供的一种API接口&#xff0c;通过调用API接口&#xff0c;开发者可以获取1688商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片&#xff0c;重量&#xff0c;详情描述等详细信息 。 获取商品详情接口API是一种用于…

《Linux内核源码分析》(3)调度器及CFS调度器

《Linux内核源码分析》(3)调度器及CFS调度器 文章目录 《Linux内核源码分析》(3)调度器及CFS调度器一、调度器1、调度器2、调度类sched_class结构体3、优先级4、内核调度策略 二、CFS调度器1、CFS调度器基本原理2、调度子系统各个组件模块3、CFS调度器就绪队列内核源码 一、调度…

影响屏蔽箱使用效果的因素有哪些?

屏蔽箱到底是用来屏蔽什么的&#xff1f;屏蔽箱主要是为无线制造行业&#xff0c;如手机、平板、遥控器、无线网卡、蓝牙设备、路由器、GPS行业、智能家居等提供隔离测试环境&#xff0c;屏蔽外界对被测产品的干扰&#xff0c;让信号经过特殊处理和被测产品通讯。 影响屏蔽效果…

Java“牵手”1688商品详情数据,1688API接口申请指南

1688平台商品详情接口是开放平台提供的一种API接口&#xff0c;通过调用API接口&#xff0c;开发者可以获取1688商品的标题、价格、库存、月销量、总销量、库存、详情描述、图片等详细信息 。 获取商品详情接口API是一种用于获取电商平台上商品详情数据的接口&#xff0c;通过…

【C++】详解声明和定义

2023年8月28日&#xff0c;周一下午 研究了一个下午才彻底弄明白... 写到晚上才写完这篇博客。 目录 声明和定义的根本区别结构体的声明和定义声明结构体 定义结构体类的声明和定义函数的定义和声明声明函数 定义函数变量声明和定义声明变量定义变量 声明和定义的根本区别 …

CSS学习笔记01

CSS笔记01 什么是CSS CSS&#xff08;Cascading Style Sheets &#xff09;&#xff1a;层叠样式表&#xff0c;也可以叫做级联样式表&#xff0c;是一种用来表现 HTML 或 XML 等文件样式的计算机语言。字体&#xff0c;颜色&#xff0c;边距&#xff0c;高度&#xff0c;宽度…

掌握C/C++协程编程,轻松驾驭并发编程世界

一、引言 协程的定义和背景 协程&#xff08;Coroutine&#xff09;&#xff0c;又称为微线程或者轻量级线程&#xff0c;是一种用户态的、可在单个线程中并发执行的程序组件。协程可以看作是一个更轻量级的线程&#xff0c;由程序员主动控制调度。它们拥有自己的寄存器上下文…

leetcode 1022.从根到叶的二进制数之和

⭐️ 题目描述 &#x1f31f; leetcode链接&#xff1a;https://leetcode.cn/problems/sum-of-root-to-leaf-binary-numbers/description/ 代码&#xff1a; class Solution { public:int sum (TreeNode* root , int num 0) {if (root nullptr) {return 0;}int cur num r…

视频汇聚/视频云存储/视频监控管理平台EasyCVR安全检查的相关问题及解决方法

安防视频监控/视频集中存储/云存储/磁盘阵列EasyCVR平台可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。平台既具备传统安…

C++day6(多态实现动物园的讲解员和动物表演的相关介绍、用函数模板实现不同数据类型的交换功能)

1.比喻&#xff1a;动物园的讲解员和动物表演 想象一下你去了一家动物园&#xff0c;看到了许多不同种类的动物&#xff0c;如狮子、大象、猴子等。现在&#xff0c;动物园里有一位讲解员&#xff0c;他会为每种动物表演做简单的介绍。 在这个场景中&#xff0c;我们可以将动…

git clone 报SSL证书问题

git命令下运行 git config --global http.sslVerify false 然后再进行重新clone代码

06.DenseCap

目录 前言泛读摘要IntroductionRelated Work小结 精读模型模型构架全卷积定位层卷积锚点边界回归边界采样双线性插值 识别网络RNN 损失函数训练与优化 实验数据集&#xff0c;预处理DenseCap评价标准基线区域和图像级统计之间的差异RPN vs EdgeBoxesQualitative results 区域ca…