初识二叉树和二叉树的基本操作

目录

一、树 

 1.什么是树

2. 与树相关的概念

二、二叉树 

1.什么是二叉树

2.二叉树特点

3.满二叉树与完全二叉树

4.二叉树性质

 相关题目:

5.二叉树的存储 

6.二叉树的遍历和基本操作 

 二叉树的遍历

二叉树的基本操作


一、树 

 1.什么是树

  • 子树是不相交的;
  • 除了根结点外,每个结点有且仅有一个父结点
  • 一棵N个结点的树有N-1条边。 

树:                                                    非树: 

       

2. 与树相关的概念

  • 结点的度:一个结点含有子树的个数称为该结点的度; 如上图:A的度为6
  • 树的度:一棵树中,所有结点度的最大值称为树的度; 如上图:树的度为6
  • 叶子结点或终端结点:度为0的结点称为叶结点; 如上图:B、C、H、I...等节点为叶结点
  • 双亲结点或父结点:若一个结点含有子结点,则这个结点称为其子结点的父结点; 如上图:A是B的父结点
  • 孩子结点或子结点:一个结点含有的子树的根结点称为该结点的子结点; 如上图:B是A的孩子结点
  • 根结点:一棵树中,没有双亲结点的结点;如上图:A
  • 结点的层次:从根开始定义起,根为第1层,根的子结点为第2层,以此类推
  • 树的高度或深度:树中结点的最大层次; 如上图:树的高度为4

二、二叉树 

1.什么是二叉树

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

  • 或者为空
  • 或者是由一个根节点加上两棵别称为左子树右子树的二叉树组成。

 

2.二叉树特点

  • 二叉树不存在度大于2的结点(树的度:一棵树中,所有结点 度的最大值 称为树的度)
  • 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树 

3.满二叉树与完全二叉树

  • 满二叉树: 一棵二叉树,如果每层的结点数都达到最大值,则这棵二叉树就是满二叉树。也就是说,如果一棵又树的层数为K,且结点总数是2^k-1,则它就是满二叉树

  • 完全二叉树: 完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从0至n-1的结点一 一对应时称之为完全二叉树。 意思就是完全二叉树的所有节点从上到下,从左到右依次排满。 要注意的是满二叉树是一种特殊的完全二又树。 

完全二叉树有一个特点,那就是如果总结点数为奇数,那么这个二叉树就只有一个度为1的节点,如果是偶数,就没有度为1的结点。 

4.二叉树性质

1. 若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有 2^{i}-1(i>0)个结点

2. 若规定只有根结点的二叉树的深度为1,则深度为K的二叉树的最大结点数是2^{k}-1(k>=0)

3. 对任何一棵二叉树, 如果其叶结点个数为 n0, 度为2的非叶结点个数为 n2,则有n0=n2+1

4. 具有n个结点的完全二叉树的深度k为\log _{_{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. 某二叉树共有 399 个结点,其中有 199 个度为 2 的结点,则该二叉树中的叶子结点数为( )
A 不存在这样的二叉树
B 200
C 198
D 199
2.在具有 2n 个结点的完全二叉树中,叶子结点个数为( )
A n
B n+1
C n-1
D n/2
3.一个具有767个节点的完全二叉树,其叶子节点个数为()
A 383
B 384
C 385
D 386
4.一棵完全二叉树的节点数为531个,那么这棵树的高度为( )
A 11
B 10
C 8
D 12 

答案:
1.B

解析:

叶子结点或终端结点:度为0的结点称为叶结点。
由前面说的二叉树性质第3点:对任何一棵二叉树, 如果其叶结点个数为 n0, 度为2的非叶结点个数为 n2,则有n0=n2+1。

所以 n2=199,n0=n2+1=200.

2.A

解析: 

设结点总数为N=2n,因为题目中说了这是一颗完全二叉树,而结点总数是偶数,那么说明这个二叉树只有一个度为1的结点。
N=n0+n1+n2 => 2n=n0+n2+1 因为n0=n2+1,所以  2n-1=n0+n0-1 => n0=n

3.B 

解析: 

N=767,767为奇数,所以这个二叉树没有度为1的结点(n1=0)
N=n0+n1+n2=n0+n0-1=767 => n0=384

4.B 

解析: 

由前面说的二叉树性质第4点:具有n个结点的完全二叉树的深度k为l\log _{_{2}}(n+1)上取整.

2^{9}< 532 <2^{10}  => 9<\log _{_{2}}532 <10,因为是上取整,那么 k=10.

5.二叉树的存储 

二叉树的存储结构分为:
顺序存储类似于链表的链式存储。二叉树的链式存储是通过一个一个的节点引用起来的,常见的表示方式有二叉和三叉表示方式(孩子表示法以及孩子双亲表示法)。 

// 孩子表示法
class Node {
    int val; // 数据域
    Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
    Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
} 
// 孩子双亲表示法
class Node {
    int val; // 数据域
    Node left; // 左孩子的引用,常常代表左孩子为根的整棵左子树
    Node right; // 右孩子的引用,常常代表右孩子为根的整棵右子树
    Node parent; // 当前节点的根节点
}

6.二叉树的遍历和基本操作 

二叉树的遍历

1.前中后序遍历

  • 前序遍历:根节点 左子树 右子树
  • 中序遍历:左子树 根节点 右子树
  • 后序遍历:左子树 右子树 根节点

2.层序遍历

自上而下,自左至右逐层访问树的结点的过程就是层序遍历

有如下二叉树,大家可用上述方法自行遍历 

前序遍历:A B D E H C F G

中序遍历:D B E H A F C G 

后序遍历:B D E H C F G A 

层序遍历:A B C D E F G H 

代码实现: 

这里先按照上图用穷举的方式快速构建一颗二叉树(不是构建二叉树的正确方法) 

public class BinaryTree {
    public static class TreeNode {
        TreeNode left;
        TreeNode right;
        char val;

        TreeNode(char val) {
            this.val = val;
        }
    }

    private TreeNode root;

    public TreeNode createTree() {
        TreeNode A = new TreeNode('A');
        TreeNode B = new TreeNode('B');
        TreeNode C = new TreeNode('C');
        TreeNode D = new TreeNode('D');
        TreeNode E = new TreeNode('E');
        TreeNode F = new TreeNode('F');
        TreeNode G = new TreeNode('G');
        TreeNode H = new TreeNode('H');

        root = A;
        A.left = B;
        A.right = C;

        B.left = D;
        B.right = E;
        C.left = F;
        C.right = G;

        E.right = H;
        return A;
    }

    //前序遍历
    public void preOrder(TreeNode root){
        if(root==null){
            return;
        }
        System.out.print(root.val+" ");
        preOrder(root.left);
        preOrder(root.right);
    }

    //中序遍历
    public void inOrder(TreeNode root){
        if (root==null){
            return;
        }
        inOrder(root.left);
        System.out.print(root.val+" ");
        inOrder(root.right);
    }

    //后序遍历
    public void postOrder(TreeNode root){
        if (root==null){
            return;
        }
        preOrder(root.left);
        preOrder(root.right);
        System.out.print(root.val+" ");
    }

}
public class Main {
    public static void main(String[] args) {
        BinaryTree binaryTree=new BinaryTree();
        BinaryTree.TreeNode root=binaryTree.createTree();

        System.out.print("前序遍历:");
        binaryTree.preOrder(root);
        System.out.println();
        System.out.print("中序遍历:");
        binaryTree.inOrder(root);
        System.out.println();
        System.out.print("后序遍历:");
        binaryTree.postOrder(root);
    }
}

运行结果:

二叉树的基本操作

1. 获取树中节点的个数

这个方法实现在这里有两种思路:

1.遍历这个树,是结就nodeSize++
2.用子问题的思路来解决:总结点数=左子树结点的个数+右子树结点的个数+根结点

    public static int nodeSize=0;
    //获取树中节点的个数(遍历每个节点)
    public void size(TreeNode root){
        if (root==null){
            return;
        }
        nodeSize++;
        size(root.left);
        size(root.right);
    }
    //用子问题的思路来解决:总节点数=左子树节点的个数+右子树节点的个数+根节点
    public int size2(TreeNode root){
        if (root==null){
            return 0;
        }

        int tmp=size2(root.left)+size2(root.right)+1;
        return tmp;
    }

2.获取叶子节点的个数

叶子结点的特点就是度为0,即其左子树和右子树都是空。

这个方法实现在这里有两种思路:

1.遍历这个树,只要root不为空且root的左子树和右子树都为空,就说明root所在的结点是叶子结点
2.用子问题的思路来解决:总叶子结点数=左子树的叶子结点+右子树的叶子结点

    public int leafSize;
    public void getLeafNodeCount(TreeNode root) {
        if(root == null) {
            return;
        }
        if(root.left == null && root.right == null) {
            leafSize++;
        }
        getLeafNodeCount(root.left);
        getLeafNodeCount(root.right);
    }

    //子问题思路:这颗树的总叶子结点数=左子树的叶子结点+右子树的叶子结点
    public int getLeafNodeCount2(TreeNode root) {
        if (root == null) {
            return 0;
        }
        if (root.left == null && root.right == null) {
            return 1;
        }
        return getLeafNodeCount2(root.left)
                + getLeafNodeCount2(root.right);
    }

3.获取第K层节点的个数

    public int getKLevelNodeCount(TreeNode root,int k){
        if (root==null){
            return 0;
        }
        if (k==1){
            return 1;
        }
        return getKLevelNodeCount(root.left,k-1)+getKLevelNodeCount(root.right,k-1);
    }

4.获取二叉树的高度

 整棵树的高度=找出 左子树的高度 和 右子树的高度 的最大值 +1(树的高度或深度:树中结点的最大层次)

    // 获取二叉树的高度
    public int getHeight(TreeNode root){
        if(root==null){
            return 0;
        }

        int leftHeight=getHeight(root.left);
        int rightHeight=getHeight(root.right);

        return Math.max(leftHeight,rightHeight)+1;
    }

5. 检测值为value的元素是否存在

1.先判断根节点的值是不是我们要找的value,如果是就返回这个root

2.如果当前根节点不是我们要找的value,那就到当前根节点的左子树去找,如果左子树找不到就去右子树找。

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

        TreeNode leftval=find(root.left,val);
        if(leftval!=null){
            return leftval;
        }

        TreeNode rightval=find(root.right,val);
        if (rightval!=null){
            return rightval;
        }

        return null;
    }

6.层序遍历

先入队根节点,然后出队,若当前根节点左右不为空,则把不为空的左右入队,出新的队头,以此类推。  

   public void levelOrder(TreeNode root) {
        if(root == null) {
            return;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            TreeNode cur = queue.poll();
            System.out.print(cur.val+" ");
            if(cur.left != null) {
                queue.offer(cur.left);
            }
            if(cur.right != null) {
                queue.offer(cur.right);
            }
        }
    }

7.判断一棵树是不是完全二叉树

1.先把根节点放到队列当中

2.队列不为空,弹出元素,带入左右(可以为空)

3.当队列弹出元素为null则停止

4.最后一步,判断当前队列是否元素都是nul,只要出现不为nul的元素,则当前二又树不是完全二叉树 

   public boolean isCompleteTree(TreeNode root) {
        if(root == null) return true;
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(root);
        while (!queue.isEmpty()) {
            TreeNode cur = queue.poll();
            if(cur != null) {
                queue.offer(cur.left);
                queue.offer(cur.right);
            }else {
                break;//结束之后  遍历队列剩下的所有元素 是不是都是null
            }
        }
        // 遍历队列剩下的所有元素 是不是都是null
        while (!queue.isEmpty()) {
            TreeNode cur = queue.poll();
            if(cur != null) {
                return false;
            }
        }
        return true;
    }

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

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

相关文章

Github 2024-04-06Rust开源项目日报Top10

根据Github Trendings的统计,今日(2024-04-06统计)共有10个项目上榜。根据开发语言中项目的数量,汇总情况如下: 开发语言项目数量Rust项目10HTML项目1Dart项目1RustDesk: 用Rust编写的开源远程桌面软件 创建周期:1218 天开发语言:Rust, Dart协议类型:GNU Affero General …

docker + miniconda + python 环境安装与迁移(详细版)

本文主要列出从安装dockerpython环境到迁移环境的整体步骤。windows与linux之间进行测试。 简化版可以参考&#xff1a;docker miniconda python 环境安装与迁移&#xff08;简化版&#xff09;-CSDN博客 目录 一、docker 安装和测试 二、docker中拉取miniconda&#xff…

C语言--指针终章

目录 1. sizeof和strlen的对⽐ 1.1 sizeof 1.2 strlen 1.3 sizeof 和 strlen的对⽐ 2. 数组和指针的理解——题目理解 2.1.sizeof 代码1&#xff1a; 代码2&#xff1a; 代码3&#xff1a; 代码4&#xff1a; 代码5&#xff08;二维数组&#xff09;&#xff1a; 2.2…

【蓝桥杯-单链表-网络寻路】

蓝桥杯-单链表-网络寻路 单链表基本操作操作一&#xff1a;向链表头插入一个数操作二:在第 k个插入的数后插入一个数操作三&#xff1a;删除第 k个插入的数后面的一个数&#xff1b; P8605 [蓝桥杯 2013 国 AC] 网络寻路 单链表基本操作 初始化有关操作 // head 表示头结点的…

Debian12 使用 nginx 与 php8.2 使用 Nextcloud

最近将小服务器升级了下系统&#xff0c;使用了 debian12 的版本&#xff0c;正好试试 nginx 和 php-fpm 这种方式运行 Nextcloud 这个私有云的配置。 一、基本系统及应用安装 系统&#xff1a;debian12 x86_64 位版本最小安装&#xff0c;安装后可根据自己需求安装一些工具&…

如何优化TCP?TCP的可靠传输机制是什么?

在网络世界中&#xff0c;传输层协议扮演着至关重要的角色&#xff0c;特别是TCP协议&#xff0c;以其可靠的数据传输特性而广受青睐。然而&#xff0c;随着网络的发展和数据量的激增&#xff0c;传统的TCP协议在效率方面遭遇了挑战。小编将深入分析TCP的可靠性传输机制&#x…

【C++初阶】 vector 在OJ中的使用

前言&#xff1a; &#x1f3af;个人博客&#xff1a;Dream_Chaser &#x1f388;博客专栏&#xff1a;C &#x1f4da;本篇内容&#xff1a;只出现一次的数字 和 杨辉三角 OJ 目录 一、只出现一次的数字 题目描述&#xff1a; 二、杨辉三角OJ 题目描述&#xff1a; 一、只…

vue快速入门(七)内联语句

注释很详细&#xff0c;直接上代码 上一篇 新增内容 button点击事件绑定内联语句写法与要求 源码 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-wid…

phpstorm设置头部注释和自定义注释内容

先说设置位置&#xff1a; PhpStorm中文件、类、函数等注释的设置在&#xff1a;setting-》Editor-》FIle and Code Template-》Includes-》PHP Function Doc Comment下设置即可&#xff0c;其中方法的默认是这样的&#xff1a; /** ${PARAM_DOC} #if (${TYPE_HINT} ! "…

【第九篇】使用BurpSuite进行编码与解码

Burp存在一个功能&#xff0c;可以识别包含不透明数据&#xff08;例如会话令牌&#xff09;的消息。 如图&#xff1a;如果 Burp 识别所选内容的编码格式&#xff0c;它会自动解码数据。解码后的文本显示在 Inspector面板中。 在编码工具模块中&#xff0c;可对数据进行重复解…

C. MEX Game 1

本题如果我们去模拟这个算法的话会很麻烦&#xff0c;也会TLE&#xff0c;首先我们想 1&#xff0c;对于alice来说&#xff0c;先取小的&#xff0c;对于bob来说先删除alic想取的下一个小的 2&#xff0c;那如果这个数多于两个&#xff0c;那也就是说&#xff0c;alice肯定能…

电工技术学习笔记——正弦交流电路

一、正弦交流电路 1. 正弦量的向量表示法 向量表示方法&#xff1a;正弦交流电路中&#xff0c;相量表示法是一种常用的方法&#xff0c;用于描述电压、电流及其相位关系。相量表示法将正弦交流信号表示为复数&#xff0c;通过复数的运算来描述电路中各种参数的相互关系 …

C/C++预处理过程

目录 前言&#xff1a; 1. 预定义符号 2. #define定义常量 3. #define定义宏 4. 带有副作用的宏参数 5. 宏替换的规则 6. 宏和函数的对比 7. #和## 8. 命名约定 9. #undef 10. 命令行定义 11. 条件编译 12. 头文件的包含 13. 其他预处理指令 总结&#x…

IP地址:是给主机配置的,还是给网卡配置的?

在探索网络的奥秘时&#xff0c;我们经常会遇到一个看似简单但又复杂的问题&#xff1a;IP地址到底是配置在主机上&#xff0c;还是配置在网卡上&#xff1f;为什么我们通常说的是“主机IP地址”呢&#xff1f;让我们一起深入探讨。 1. 网卡与IP地址 &#x1f5a5;️&#x1f…

有同学和我说,深度学习不用特征工程,只有浅层机器学习方法采用特征工程,我说你误会了,我给你好好解释吧!!

1. 通俗解释 浅层机器学习算法&#xff08;如逻辑回归、决策树、支持向量机等&#xff09;和深度学习算法&#xff08;如神经网络&#xff09;在特征工程上的依赖性确实存在一些差异。 浅层机器学习算法的特征工程依赖性&#xff1a; 浅层算法通常需要手工选择和设计特征&…

lua学习笔记5(分支结构和循环的学习)

print("*****************分支结构和循环的学习******************") print("*****************if else语句******************") --if 条件 then end a660 b670 --单分支 if a<b thenprint(a) end --双分支 if a>b thenprint("满足条件")…

RGB三通道和灰度值的理解

本文都是来自于chatGPT的回答!!! 目录 Q1:像素具有什么属性?Q2:图像的色彩是怎么实现的?Q3:灰度值和颜色值是一个概念吗?Q4:是不是像素具有灰度值&#xff0c;也有三个颜色分量RGB&#xff1f;Q5:灰度图像是没有色彩的吗&#xff1f;Q6: 彩色图像是既具有灰度值也具有RGB三…

11_printf函数移植串口通信

printf函数移植串口通信 printf函数移植串口通信串口显示汉字乱码问题解决代码 printf函数移植串口通信 MicroLIB是Keil为嵌入式平台优化的一个精简库 --no-multibyte-chars 串口显示汉字乱码问题解决 法一 法二 代码 主函数 #include "stm32f10x.h" …

[StartingPoint][Tier1]Sequel

Task 1 During our scan, which port do we find serving MySQL? (在扫描过程中&#xff0c;我们发现哪个端口为 MySQL 提供服务&#xff1f;) 3306 Task 2 What community-developed MySQL version is the target running? (目标正在运行哪个社区开发的 MySQL 版本&…

详解 Redis 在 Centos 系统上的安装

详解 Redis 在 Centos 系统上的安装 1. 使用 yum 安装 Redis 5 如果是Centos8&#xff0c;yum 仓库中默认的 redis 版本就是5&#xff0c;直接 yum install 即可 如果是Centos7, yum 仓库中默认的 redis 版本是3系列&#xff0c;版本就比较老 使用yum list | grep redis命令…