手撕二叉树(图解+代码)

这篇具有很好参考价值的文章主要介绍了手撕二叉树(图解+代码)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在学习二叉树之前,我们有必要了解一下树的概念和常用术语。接下来以下面这棵树为例来回顾下树相关概念:
手撕二叉树(图解+代码)

🌳1.树的概念

树的概念:一种非线性的数据结构,由n(n >=0)个节点组成的一个具有层次关系的集合。 树的术语:

  • 节点的度 一个节点含有子树的个数,例如上图中A的度为6.
  • 树的度 树上所有节点的度的最大值,例如上图中树的度为6.
  • 叶子结点 度为0的节点,例如上图中的K、L、M…
  • 根节点 树中没有双亲节点的节点。例如,上图中树的根节点为A。、
  • 子节点 一个节点含有的子树的根,如上如,B是A的子节点
  • 父节点 一个节点有子节点,则称这个节点为其子节点的父节点。如上图A时B的父节点

🌳2.二叉树的概念及性质

🍎2.1 二叉树的概念

二叉树是树的一种特殊形式,空树是二叉树,或者树中所有节点的度小于二的树称为二叉树。如下图所示,接下来介绍二叉树我们以这张图片上的树形为准:

手撕二叉树(图解+代码)

🍎2.2 二叉树的性质

  • 规定根节点的层次为1,则一颗非空二叉树的第 i 层上最多有:2k-1个节点
  • 规定根节点的二叉树深度为1,则深度为k的那层的二叉树的最大节点数为:2k-1(k>=0)
  • 对于任何一颗 二叉树 ,如果器叶子节点数为n0,度为2的节点数为n2,则有n0 = n2 + 1
  • 具有 n 个节点的完全二叉树的深度k 为:log2(n+1) 向上取整.

🌳3.二叉树的基本操作

🍎3.1 二叉树的遍历

🌳前序遍历
前序遍历的二叉树将按照先访问根节点,再访问左子树,最后访问右子树的过程递归进行,最终遍历结束所有的节点。
前序遍历的过程如下:
手撕二叉树(图解+代码)

public void preOrder(TreeNode root) {
	if(root != null) {
		System.out.print(root.val+" ");
		preOrder(root.left);
		preOrder(root.right);		
	}	
}

按照前序遍历结果,则上述二叉树的遍历结果为:A->B->D->E->H->C->F->G

🌳中序遍历
中序遍历的二叉树将按照先访问左子树,再访问根节点,最后访问右子树的过程递归进行,最终遍历结束所有的节点。
中序遍历的过程如下:
手撕二叉树(图解+代码)

public void inOrder(TreeNode root) {
    if (root != null) {
        inOrder(root.left);
        System.out.print(root.val + " ");
        inOrder(root.right);
    } }

根据上图的遍历过程,我们可以得到上述二叉树的中序遍历结果为:D->B->E->H->A->F->C->G

🌳后序遍历
后序遍历的二叉树将按照先访问左子树,再访问右子树,最后访问根节点的过程递归进行,最终遍历结束所有的节点。
后续遍历的过程如下:
手撕二叉树(图解+代码)

    public void postOrder(TreeNode root) {
        if (root != null) {
            postOrder(root.left);
            postOrder(root.right);
            System.out.print(root.val + " ");
        }
    }

由上图后续遍历过程可知,图中二叉树的遍历结果为:D->H->E->B->F->G->C->A

🌳层次遍历
二叉树的层次遍历即按照二叉树的层次顺序从左到右遍历节点,过程如下图所示:
手撕二叉树(图解+代码)
因为二叉树的遍历无法直接按照遍历顺序进行层次节点的访问,因此我们需要借助队列的这种数据结构来实现二叉树的层次遍历。层次遍历的原理即上述二叉树的详细入出队列过程如下:
手撕二叉树(图解+代码)

    public void levelOrder(TreeNode root) {
        ArrayDeque<TreeNode> charQueue = new ArrayDeque<>();  //创建一个队列
        charQueue.offer(root);  //将根节点入队列
        while(!charQueue.isEmpty()) {
            TreeNode pollNode = charQueue.poll();	//只要队列不为空,就从队列中取出节点访问
            System.out.print(pollNode.val + " ");
            if(pollNode.left != null) {	
                charQueue.offer(pollNode.left);
            }
            if(pollNode.right != null) {
                charQueue.offer(pollNode.right);
            }
        }
    }

🍎3.2 获取树中节点的个数

我们可以通过定义计数器以及任何一种遍历方式,拿到二叉树的节点个数,这种方法很简单,那么有没有什么别的方法可以不用定义计数器就获取到节点的个数呢?
不妨这样去向,从根节点开始,这颗二叉树的节点个数等于左子树+右子树+根节点;而对于左子树来说,左子树的节点个数同样等于它的左子树+有稀疏+根节点的个数。既然这样,我们能否通过直接返回节点个数的方法直接求出总的节点数呢》显而易见,按照上面的方法定义递归算法,可以很容易实现这件事情:

    public int countNode(TreeNode root) {
        if (root == null) {
            return 0;
        }
        int leftCount = countNode(root.left);
        int rightCount = countNode(root.right);
        return leftCount + rightCount + 1;
    }

这种求节点个数的原理如下图所示:
手撕二叉树(图解+代码)

🍎3.3 获取叶子节点的个数

与上边求节点的个数类似,我们让当前根节点判断是否有左右子树即可。
原理与上边统计节点个数的原理相同,这里就不画图了。

    public int getLeafNodeCount(TreeNode root) {
        if(root == null) {
            return 0;
        }
        if(root.left == null && root.right == null) {
            return 1;
        }
        int leftLeafCount = getLeafNodeCount(root.left);
        int rightLeafCount = getLeafNodeCount(root.right);
        return leftLeafCount + rightLeafCount;
    }

🍎3.4 获取第K层节点的个数

若规定二叉树根节点的层次为1,则对根节点层次来说,求得是其第k层的节点个数;对第二层次来说求的是其第k-1层的节点个数…,那么,我们使用递归算法,当k的相对值变为1时,则返回1代表第k层上节点的个数,将左右子树的值相加返回即可.

/**
 * 求二叉树第k层上的节点的个数  
 * @param root  二叉树的根节点  
 * @param k 求解的层数  
 * @return 返回节点个数  
 */
  public int getLevelNodeCount(TreeNode root, int k) {
    if (root == null) {
        return 0;
    }
    if (k == 1) {
        return 1;
    }
    int leftCount = getLevelNodeCount(root.left, k - 1);
    int rightCount = getLevelNodeCount(root.right, k - 1);
    return leftCount + rightCount; }

这个求解过程如下图所示:
手撕二叉树(图解+代码)

🍎3.5 获取二叉树的高度

某棵二叉树的高度等于它的左子树高度的和右子树高度的最大值加上自己,即高度height = leftTree + rightTree + 1。这仍然是典型的递归算法。当左子树或者右子树为null时,说明二叉树的这一层已经没有节点了,那么返回给上一层递归结果0即可。这个递归算法的程序设计如下:

/**
 * 获取二叉树的高度  *  
 * @param root 二叉树的根节点 
 * @return 返回二叉树的高度 
 */ 
 public int getHeight(TreeNode root) {
    if (root == null) {
        return 0;
    }
    int leftTreeHeight = getHeight(root.left);
    int rightTreeHeight = getHeight(root.right);
    return Math.max(leftTreeHeight, rightTreeHeight) + 1; 
 }

这个递归过程如下图所示:
手撕二叉树(图解+代码)

🍎3.6 检查值为value的元素是否存在

遍历二叉树的所有节点,如果存在值为value的节点,则返回这个节点,否则返回null。检查的过程为,检查根节点的值是否为value;检查左子树中是否存在;检查右子树中是否存在。递归算法的程序设计如下:

/**
 * 查找二叉树中是否存在值为value的节点
 *  
 * @param value 待查找的值  
 * @return 返回查找结果  
 */
 public TreeNode getValNode(TreeNode root, char value) {
    //如果遍历到最底层还没有找到,返回null
    if (root == null) {
        return null;
    }
    if(root.val == value) {
        return root;
    }
    //从左子树中查找
    TreeNode valNodeInL = getValNode(root.left, value);
    if(valNodeInL != null) {
        return valNodeInL;
    }
    //从右子树中查找
    TreeNode valNodeInR = getValNode(root.right, value);
    if(valNodeInR != null) {
        return valNodeInR;
    }
    return null; 
   }

这个算法的递归过程与先序遍历的过程类似。可以看上边先序遍历的图。

🍎3.7 层次遍历

所谓层析遍历,就是指将二叉树从左到右从上到下依次遍历。为了实现这种遍历效果,我们需要使用队列这种数据结构将当前节点的左右子树根节点依次入栈并在出栈式再依次将出战节点的左右子树根节点入栈,依次进行下去,直到当前栈为空。该算法的程序设计如下:

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

该算法的运行过程如下:
手撕二叉树(图解+代码)

🍎3.8 判断二叉树是不是完全二叉树

我们将该二叉树的依次按照层次遍历的顺序入队列(包含最后一层的左右空子树),在出队列时进行判断,如果出队列的节点为null,就停止入队列,并检查队列中剩余节点是否还有非空节点,如果有非空节点,说明这不是一个完全二叉树。例如,下面的这几种二叉树都不是完全二叉树,均满足上述的判定方法:
手撕二叉树(图解+代码)文章来源地址https://www.toymoban.com/news/detail-421543.html

public boolean isCompleteTree(TreeNode root) {
    if (root == null) {
        return false;
    }
    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root);
    while (!queue.isEmpty()) {
        TreeNode poll = queue.poll();   //如果在出队列时遇到null,则停止入队列
        if (poll != null) {
            queue.offer(poll.left);
            queue.offer(poll.right);
        } else {
            break;
        }
    }
    while (!queue.isEmpty()) {
        if (queue.poll() != null) { //如果队列中剩余节点还有非空的,就说明这不是一颗完全二叉树
            return false;
        }
    }
    return true;
 }

到了这里,关于手撕二叉树(图解+代码)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数据结构---手撕图解二叉树(含大量递归图解)

    二叉树的几乎所有实现都是依靠递归实现,递归的核心思路是把任何一个二叉树看成根和左右子树,而二叉树递归的核心玩法就是把二叉树的左右子树再看成根,再找左右子树,再看成根… 因此,解决二叉树问题实际上要把二叉树转换成一个一个子树的过程,找到一个一个的

    2024年02月16日
    浏览(28)
  • 手撕二叉平衡树

    今天给大家带来的是平衡树的代码实现,如下: 这个仅仅是平衡树的插入,其实二叉平衡树的插入并不难,逻辑就是那么几个,但是难得是细节处的实现,尤其是平衡因子更新的那一块,特别的容易弄混人,只要记住四种模型就可以了。两种单旋,两种双旋,还是有点难以理

    2024年02月10日
    浏览(29)
  • 线索二叉树(图解+完整代码)

    目录 ⚽1.问题 🏐2.线索化 🏀 3.线索化带来的问题与解决 🥎4.完整代码 我们的二叉树学到现在,会产生两个问题: 在n个结点的二叉树中,必定有n+1个空链域(叶子结点的左右子树空间浪费了) 二叉树的遍历,无论是递归还是非递归算法,效率都不算高。 那我们能不能利用

    2024年02月03日
    浏览(33)
  • 【算法与数据结构】二叉树的三种遍历代码实现(下)—— 非递归方式实现(大量图解)

     上篇: 【算法与数据结构】二叉树的三种遍历代码实现(上)—— 用递归序知识点讲解_Hacynn的博客-CSDN博客 https://blog.csdn.net/zzzzzhxxx/article/details/133609612?spm=1001.2014.3001.5502 目录 前言 1、先序遍历 1.1、详细图解描述 1.2、先序遍历非递归代码实现  2、中序遍历 2.1、详细图解描

    2024年02月08日
    浏览(28)
  • 手撕链式二叉树(二)—【C语言】

    链式二叉树(一)         http://t.csdn.cn/HWu6E 目录 1. 二叉树找值为x的节点 代码实现分析  代码实现 递归展开图 2. 求二叉树层数 代码思路分析 代码实现   3. 二叉树的销毁 代码思路分析 代码实现 运行结果 4. 二叉树的一些OJ题目 1. 单值二叉树                      OJ链接

    2024年02月06日
    浏览(40)
  • 带你手撕链式二叉树—【C语言】

    普通二叉树的增删查改没有意义?那我们为什么要先学习普通二叉树呢? 给出以下两点理由: 1.为后面学习更加复杂的二叉树打基础。(搜索二叉树、ALV树、红黑树、B树系列—多叉平衡搜索树) 2.有很多二叉树的OJ算法题目都是出在普通二叉树的基础上 让我们开始数据结构

    2024年02月06日
    浏览(30)
  • 【数据结构】二叉树篇|超清晰图解和详解:二叉树的最近公共祖先

    博主简介: 努力学习的22级计算机科学与技术本科生一枚🌸 博主主页: @是瑶瑶子啦 每日一言🌼: 你不能要求一片海洋,没有风暴,那不是海洋,是泥塘——毕淑敏 🔗236. 二叉树的最近公共祖先 注意:祖先是 包括自身 的! 🍊首先要明白,当 root为p,q的最近祖先节点 ,只

    2024年02月12日
    浏览(40)
  • 【数据结构】---几分钟简单几步学会手撕链式二叉树(下)

    👧个人主页:@小沈熬夜秃头中୧⍤⃝❅ 😚小编介绍:欢迎来到我的乱七八糟小星球🌝 📋专栏:数据结构 🔑本章内容:手撕链式二叉树 送给各位💌:成为更好的自己才是应该做的事 记得 评论📝 +点赞👍 +收藏😽 +关注💞哦~ 提示:以下是本篇文章正文内容,下面案例可

    2024年02月08日
    浏览(32)
  • 【数据结构】---几分钟简单几步学会手撕链式二叉树(上)

    👧个人主页:@小沈熬夜秃头中୧⍤⃝❅ 😚小编介绍:欢迎来到我的乱七八糟小星球🌝 📋专栏:数据结构 🔑本章内容:手撕链式二叉树 送给各位💌:我从没觉得孤独 说的浪漫点 我完全自由 记得 评论📝 +点赞👍 +收藏😽 +关注💞哦~ 提示:以下是本篇文章正文内容,下

    2024年02月07日
    浏览(27)
  • 二叉树创建的两种方法(图解)

            目录 一、括号表示法 (1)括号表示法构建二叉树的算法思路及算法实现 (2)图解括号表示法构建二叉树 (3)测试程序  二、扩展二叉树 (1)扩展二叉树构建二叉树的算法思路及算法实现 (2)测试程序         二叉树的创建方法有很多种,在这里我介绍两种

    2024年02月06日
    浏览(39)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包