一篇文章带你掌握二叉树(附带二叉树基本操作完整代码演示,和两种思路)

【本长内容】
1. 掌握树的基本概念
2. 掌握二叉树概念及特性
3. 掌握二叉树的基本操作
4. 完成二叉树相关的面试题练习

1. 树形结构

1.1 概念


树是一种非线性的数据结构,它是由n(n>=0)个有限结点组成一个具有层次关系的集合。把它叫做树是因为它看起来像一棵倒挂的树,也就是说它是根朝上,而叶朝下的。它具有以下的特点:
1.有一个特殊的结点,称为根结点,根结点没有前驱结点
2.除根结点外,其余结点被分成M(M > 0)个互不相交的集合T1、T2、......、Tm,其中每一个集合Ti (1 <= i <=m) 又是一棵与树类似的子树。每棵子树的根结点有且只有一个前驱,可以有0个或多个后继.

3.树是递归定义的。

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

1.2 概念

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

树的高度或深度:树中结点的最大层次; 如上图:树的高度为4
树的以下概念只需了解,在看书时只要知道是什么意思即可:
非终端结点或分支结点:度不为0的结点; 如上图:D、E、F、G...等节点为分支结点
兄弟结点:具有相同父结点的结点互称为兄弟结点; 如上图:B、C是兄弟结点
堂兄弟结点:双亲在同一层的结点互为堂兄弟;如上图:H、I互为兄弟结点
结点的祖先:从根到该结点所经分支上的所有结点;如上图:A是所有结点的祖先
子孙:以某结点为根的子树中任一结点都称为该结点的子孙。如上图:所有结点都是A的子孙
森林:由m(m>=0)棵互不相交的树组成的集合称为森林

1.3 树的应用

2. 二叉树

2.1 概念

一棵二叉树是结点的一个有限集合,该集合:
1. 或者为空
2. 或者是由一个根节点加上两棵别称为左子树和右子树的二叉树组成。

从上图可以看出:
1. 二叉树不存在度大于2的结点
2. 二叉树的子树有左右之分,次序不能颠倒,因此二叉树是有序树
注意:对于任意的二叉树都是由以下几种情况复合而成的:

2.2 两种特殊的二叉树


1. 满二叉树: 一棵二叉树,如果每层的结点数都达到最大值,则这棵二叉树就是满二叉树。也就是说,如果一棵二叉树的层数为K,且结点总数是 ,则它就是满二叉树。
2. 完全二叉树: 完全二叉树是效率很高的数据结构,完全二叉树是由满二叉树而引出来的。对于深度为K的,有n个结点的二叉树,当且仅当其每一个结点都与深度为K的满二叉树中编号从0至n-1的结点一一对应时称之为完全二叉树。 要注意的是满二叉树是一种特殊的完全二叉树。

2.3 二叉树的性质


1. 若规定根结点的层数为1,则一棵非空二叉树的第i层上最多有 (i>0)个结点
2. 若规定只有根结点的二叉树的深度为1,则深度为K的二叉树的最大结点数是 (k>=0)
3. 对任何一棵二叉树, 如果其叶结点个数为 n0, 度为2的非叶结点个数为 n2,则有n0=n2+1
4. 具有n个结点的完全二叉树的深度k为 上取整
5. 对于具有n个结点的完全二叉树,如果按照从上至下从左至右的顺序对所有节点从0开始编号,则对于序号为i的结点有:
若i>0,双亲序号:(i-1)/2;i=0,i为根结点编号,无双亲结点
若2i+1<n,左孩子序号:2i+1,否则无左孩子
若2i+2<n,右孩子序号:2i+2,否则无右孩子

2.4 二叉树的存储


二叉树的存储结构分为:顺序存储和类似于链表的链式存储。
顺序存储在下节介绍。
二叉树的链式存储是通过一个一个的节点引用起来的,常见的表示方式有二叉和三叉表示方式,具体如下:

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

孩子双亲表示法后序在平衡树位置介绍,本文采用孩子表示法来构建二叉树。

2.5 二叉树的基本操作


2.5.1 前置说明


在学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。由于现在大家对二叉树结构掌握还不够深入,为了降低大家学习成本,此处手动快速创建一棵简单的二叉树,快速进入二叉树操作学习,等二叉树结构了解的差不多时,我们反过头再来研究二叉树真正的创建方式。

public class BinaryTree{
  public static class BTNode{
    BTNode left;
    BTNode right;
    int value;
   
    BTNode(int value){
      this.value = value;
   }
 }
 
  private BTNode root;

 
  public void createBinaryTree(){
    BTNode node1 = new BTNode(1);
    BTNode node1 = new BTNode(2);
    BTNode node1 = new BTNode(3);
    BTNode node1 = new BTNode(4);
    BTNode node1 = new BTNode(5);
    BTNode node1 = new BTNode(6);
   
    root = node1;
    node1.left = node2;
    node2.left = node3;
    node1.right = node4;
    node4.left = node5;
    node5.right = node6;
 }
}

注意:上述代码并不是创建二叉树的方式,真正创建二叉树方式后序详解重点讲解。
再看二叉树基本操作前,再回顾下二叉树的概念,二叉树是:

1. 空树
2. 非空:根节点,根节点的左子树、根节点的右子树组成的

从概念中可以看出,二叉树定义是递归式的,因此后序基本操作中基本都是按照该概念实现的.

2.5.2 二叉树的遍历


1. 前中后序遍历
学习二叉树结构,最简单的方式就是遍历。所谓遍历(Traversal)是指沿着某条搜索路线,依次对树中每个结
点均做一次且仅做一次访问。访问结点所做的操作依赖于具体的应用问题(比如:打印节点内容、节点内容加
1)。 遍历是二叉树上最重要的操作之一,是二叉树上进行其它运算之基础。

在遍历二叉树时,如果没有进行某种约定,每个人都按照自己的方式遍历,得出的结果就比较混乱,如果按照某种规则进行约定,则每个人对于同一棵树的遍历结果肯定是相同的。如果N代表根节点,L代表根节点的左子树,R代表根节点的右子树,则根据遍历根节点的先后次序有以下遍历方式:
NLR:前序遍历(Preorder Traversal 亦称先序遍历)——访问根结点--->根的左子树--->根的右子树。
LNR:中序遍历(Inorder Traversal)——根的左子树--->根节点--->根的右子树。
LRN:后序遍历(Postorder Traversal)——根的左子树--->根的右子树--->根节点。

 public void preOrder(TreeNode root){
        if(root==null){
            return;
        }
        System.out.println(root);
        preOrder(root.left);
        preOrder(root.right);
    }
    public void inOrder(TreeNode root){
        if(root==null){
            return;
        }
        inOrder(root.left);
        System.out.println(root);
        inOrder(root.right);
    }
    public void postOrder(TreeNode root){
        if(root==null){
            return;
        }
        postOrder(root.left);
        postOrder(root.right);
        System.out.println(root);
    }

2. 层序遍历
层序遍历:除了先序遍历、中序遍历、后序遍历外,还可以对二叉树进行层序遍历。设二叉树的根节点所在层数为1,层序遍历就是从所在二叉树的根节点出发,首先访问第一层的树根节点,然后从左到右访问第2层上的节点,接着是第三层的节点,以此类推,自上而下,自左至右逐层访问树的结点的过程就是层序遍历。

class Solution {
    public List<List<Integer>> levelOrderBottom(TreeNode root) {
        List<List<Integer>> lists = new LinkedList<>(); 
        if(root==null){
            return lists;
        }
    Queue<TreeNode> queue = new LinkedList<TreeNode>();
    queue.offer(root);
    while(!queue.isEmpty()){
    List<Integer> list = new ArrayList<Integer>();
    int size =queue.size();
    for(int i =0;i<size; i++){
        TreeNode node = queue.poll();
        list.add(node.val);
        TreeNode left = node.left;
        TreeNode right = node.right;
        if (left != null) {
                    queue.offer(left);
                }
        if (right != null) {
                    queue.offer(right);
                }
    }
    lists.add(list);
    list.add(list);
    }
    return lists;
    }

2.5.3 二叉树的基本操作

 获取树中节点的个数

void size(TreeNode root) {
    if(root==null){
        return;
    }
    nodeSize++;
    size(root.left);
    size(root.right);
}//遍历方法

int size(TreeNode root) {
    if(root==null){
        return 0;
    }
    return size2(root.left) + size2(root.right)+1;
}//子问题方法

获取叶子节点的个数

void getLeafNodeCount1(TreeNode root) {
     if(root.left==null && root.right == null){
       leafSize++;
       return;
    }
    getLeafNodeCount1(root.left);
    getLeafNodeCount1(root.right);
}//遍历思路
int getLeafNodeCount2(TreeNode root) {
    if(root.left == null && root.right == null){
        return 1;
    }
    return getLeafNodeCount2(root.left) + getLeafNodeCount2(root.right);
}//子问题思路

获取第K层节点的个数
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);
}//
 获取二叉树的高度
int getHeight(TreeNode root) {
    if(root==null){
        return 0;
    }
    int lefttree = getHeight(root.left);
    int righttree = getHeight(root.right);
    return righttree>lefttree ? righttree +1:lefttree+1;
}
 检测值为value的元素是否存在
TreeNode find(TreeNode root, char val) {
if(root==null){
    return null;
}
if(root.val==val){
    return root;
}
TreeNode ret1 = find(root.left,val);
if(ret1 != null){
    return ret1;
}
TreeNode ret2 = find(root.right.right,val);
if(ret2 != null){
    return ret2;
}
return null;
    }
 判断一棵树是不是完全二叉树
boolean isCompleteTree(TreeNode root) {

    Queue<TreeNode> queue = new LinkedList<>();
    queue.add(root);
    while(!queue.isEmpty()){
       TreeNode ret =queue.poll();
       if(ret != null){
           queue.offer(ret.left);
           queue.offer(ret.right);
       }
       else {
           break;
       }
    }
    while(!queue.isEmpty())
    {
        if(queue.poll() != null){
            return false;
        }
    }
    return true;
}

二叉树的概念比较简单,但是由于是递归,所以代码的难度和理解都比较难,需要我们花时间去理解和掌握.

大家看完博客以后可以去多写习题来巩固.

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

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

相关文章

考研数据结构——中缀转后缀(用栈实现)

算法目的&#xff1a;给计算机一个中缀表达式&#xff0c;输出一个后缀表达式。 考点&#xff1a;考察进行到某一步时&#xff0c;栈内的情况是怎么样的&#xff0c;选择题。 学习目标&#xff1a;能用笔算的方式模拟整个过程&#xff0c;不需要会写代码。 过程&#xff1a;…

分类预测 | Matlab实现GWO-LSSVM灰狼算法优化最小二乘支持向量机数据分类预测

分类预测 | Matlab实现GWO-LSSVM灰狼算法优化最小二乘支持向量机数据分类预测 目录 分类预测 | Matlab实现GWO-LSSVM灰狼算法优化最小二乘支持向量机数据分类预测分类效果基本介绍程序设计参考资料 分类效果 基本介绍 1.Matlab实现GWO-LSSVM灰狼算法优化最小二乘支持向量机数据…

每日面经分享(Git经典题目,Git入门)

1. GitHub是什么 a. Git是一个分布式版本控制系统&#xff0c;作用是跟踪、管理和协调软件开发项目中的代码更改。 b. 提供了一种有效的方式来管理代码的版本历史&#xff0c;以及多人协作开发的能力。 2. Git的作用有哪些 a. 版本控制&#xff1a;Git可以记录每次代码更改的…

Anaconda换源和常用命令

设置Anaconda国内镜像加速下载 使用conda install python包非常便捷&#xff0c;但由于官方服务器位于国外&#xff0c;下载速度较慢。为了提升下载速度&#xff0c;国内清华大学提供了Anaconda的仓库镜像。 要将Anaconda设置为使用国内镜像&#xff0c;特别是清华镜像源&…

[java]网络编程

网络编程概述 计算机网络&#xff1a; 把分布在不同地理区域的具有独立功能的计算机,通过通信设备与线路连接起来&#xff0c;由功能完善的软件实现资源共享和信息传递的系统。 Java是 Internet 上的语言&#xff0c;它从语言级上提供了对网络应用程序的支持&#xff0c;程序…

软考之零碎片段记录(六)+复习巩固

A. 上新 一、关系模式 1. 决定属性 AB->C,函数依赖左侧出现为决定属性 AB->C,函数依赖右侧出现为非决定属性 候选键在决定属性中挑选&#xff0c;AB->C, CD->B中&#xff0c;A,D为侯选建 二、授权SQL 将权限授予用户&#xff08;grant <权限> on&#xf…

插入排序解读

在众多的排序算法中&#xff0c;插入排序以其直观易懂和在某些特定场景下的高效性而备受青睐。今天&#xff0c;我们就来深入探索一下插入排序的原理、实现方式以及它的优缺点。 一、算法原理 插入排序相当于打牌中抓牌插入的方式。插入排序的工作方式是通过构建有序序列&…

[计算机网络] 当输入网址到网页

HTTP 首先&#xff0c;对URL进行解析&#xff0c;URL包含了Web服务器和对应的文件&#xff08;文件路径&#xff09; URL是请求服务器中的文件资源 通过Web服务器和对应文件来生产HTTP包&#xff08;超文本传输协议&#xff09; DNS 根据域名查询对应的IP地址 域名的层级 根…

前端验证码

一、基础验证码 gVerify.js&#xff1a; !(function (window, document) {function GVerify(options) { //创建一个图形验证码对象&#xff0c;接收options对象为参数this.options { //默认options参数值id: "", //容器IdcanvasId: "verifyCanvas", //ca…

JavaScript常用知识面试题day01

大家好我是没钱的君子下流坯&#xff0c;用自己的话解释自己的知识 前端行业下坡路&#xff0c;甚至可说前端已死&#xff0c;我还想在前段行业在干下去&#xff0c;所以从新开始储备自己的知识。 从CSS——>Javascript——>VUE2——>Vuex、VueRouter、webpack——>…

【项目实战】——商品管理的制作完整代码

&#x1f468;‍&#x1f4bb;个人主页&#xff1a;开发者-曼亿点 &#x1f468;‍&#x1f4bb; hallo 欢迎 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍&#x1f4bb; 本文由 曼亿点 原创 &#x1f468;‍&#x1f4bb; 收录于专栏&#xff1a…

阿里云邮件服务器多少钱?邮件服务器租用费用

阿里云邮件服务器租用费用&#xff0c;2核2G3M带宽99元一年、2核4G4M服务器199元一年&#xff0c;不只是云服务器ECS&#xff0c;还可以选择轻量应用服务器。 0、在阿里云CLUB中心领取 aliyun.club 当前最新的优惠券和服务器报价单 1、阿里云服务器ECS经济型e实例&#xff0c;2…

Splunk Attack Range:一款针对Splunk安全的模拟测试环境创建工具

关于Splunk Attack Range Splunk Attack Range是一款针对Splunk安全的模拟测试环境创建工具&#xff0c;该工具完全开源&#xff0c;目前由Splunk威胁研究团队负责维护。 该工具能够帮助广大研究人员构建模拟攻击测试所用的本地或云端环境&#xff0c;并将数据转发至Splunk实例…

基于SpringBoot+微信小程序的农产品销售平台

一、项目背景介绍&#xff1a; 随着人们收入的不断增加、生活水平的普遍提高,对生活质量的要求也日益凸显。而作为关乎每个人的生命、健康安全的食品卫生、质量无疑更被人们所重视。所以,… 2. 其他国家的绿色有机食品所占其国家食品市场比重比较大,如德国在99年便已达到40%,美…

差异创意搜索算法(DCS)-2024年SCI一区新算法-公式原理详解与性能测评 Matlab代码免费获取

声明&#xff1a;文章是从本人公众号中复制而来&#xff0c;因此&#xff0c;想最新最快了解各类智能优化算法及其改进的朋友&#xff0c;可关注我的公众号&#xff1a;强盛机器学习&#xff0c;不定期会有很多免费代码分享~ 目录 原理简介 一、种群初始化 二、差异化知识…

ThinkPHP代码审计(1) 不安全的SQL注入PHP反序列化链子phar利用简单的CMS审计实例

ThinkPHP代码审计(1) 不安全的SQL注入&PHP反序列化链子phar利用&简单的CMS审计实例 文章目录 ThinkPHP代码审计(1) 不安全的SQL注入&PHP反序列化链子phar利用&简单的CMS审计实例一.Thinkphp5不安全的SQL写法二.Thinkphp3 SQL注入三.Thinkphp链5.1.x结合phar实现…

可变参数模板

可变参数模板的概念 可变参数模板是C11新增的最强大的特性之一&#xff0c;它对参数高度泛化&#xff0c;能够让我们创建可以接受可变参数的函数模板和类模板。 在C98/03中&#xff0c;类模板和函数模板中只能包含固定数量的模板参数&#xff0c;可变模板参数无疑是一个巨大的…

MicroPython 树莓派 RP2 入门教程

系列文章目录 前言 Raspberry Pi Pico 开发板&#xff08;图片来源&#xff1a;Raspberry Pi 基金会&#xff09;。 以下是 Raspberry Pi RP2xxx 板的快速参考资料。如果您是第一次使用该开发板&#xff0c;了解微控制器的概况可能会对您有所帮助&#xff1a; 一、关于 RP2xxx…

MPLS-基础、LSR、LSP、标签、体系结构

MPLS技术 MPLS基础 MPLS&#xff1a;转发数据时&#xff0c;只在网络边缘分析IP报文头&#xff0c;不在每一跳都分析&#xff0c;节约了转发时间。 MPLS&#xff1a;Multiprotocol Label Switching&#xff0c;多协议标签交换骨干网技术。主要应用&#xff1a;VPN、流量工程…

Day5-Hive的结构和优化、数据文件存储格式

Hive 窗口函数 案例 需求&#xff1a;连续三天登陆的用户数据 步骤&#xff1a; -- 建表 create table logins (username string,log_date string ) row format delimited fields terminated by ; -- 加载数据 load data local inpath /opt/hive_data/login into table log…