目录

1 背景知识:树(Tree)

2 何为二叉树(Binray Tree)

2.1 二叉树的概念与结构

2.2 满二叉树与完全二叉树

2.3 二叉树的三种遍历方式

3 二叉树及其遍历的简单实现(Java)


1 背景知识:树(Tree)

在之前的笔记中,我们介绍的链表、栈、队列、数组和字符串都是以线性结构来组织数据的。本篇笔记要介绍的采用的是树状结构,这是一种非线性的数据组织形式。

树结构由节点构成,且不存在。我们曾在线性表型的数据结构中介绍过循环链表和循环队列,这两种数据结构使得存储容器中的元素形成一个闭环,具体可参看“数据结构学习笔记”系列的相关博文,链接贴在下面:

链表:https://blog.csdn.net/weixin_45370422/article/details/116573863

队列:https://blog.csdn.net/weixin_45370422/article/details/117376241

树状结构与线性结构最重要的区别在于:树只能有分叉,不能有闭环。如下图所示:

树结构不允许有环其实是树的层级性决定的。树结构中最顶端的结点是根节点, 根节点即整棵树的顶级父节点。除了根节点只有子节点,最底层的节点只有父节点,其余各层的节点都是上层节点的子节点、下层节点的父节点。也就是说,树中的数据只与其上下层的数据有关,同层数据间不能有直接联系,这也就是树结构不能有环的原因。

树层级的多少往往被描述为树的高度(height),由于我们是从上往下观察树结构的,因此也被描述为树的深度(depth)。上面图示中两颗树的深度都是3.

2 何为二叉树(Binray Tree)

2.1 二叉树的概念与结构

二叉树顾名思义,即每个父节点最多只有两个分叉的树,这是数据结构领域使用频率极高的一种树结构,这与我们常常用二元对立的观点认识世界的思维习惯有关。

二叉树的结构不仅具有层级性,还具有递归性,一个父节点连接左子节点右子节点,而左右子节点又可以作为父节点再各自连接两个子节点,以此类推。因此二叉树是一种层次嵌套的数据结构,除了根节点外,树中任意一个父节点都能作为一棵子树,位于上层父节点左侧的子树被称为左子树,位于右侧的子树被称为右子树

二叉树体现了人们用二元思维认识自然的方式。笔者的本行是语言学,语言学界主流的对句法结构的分析方法就是类似于二叉树的二分法。拿汉语的句法结构来说,有主谓、述宾、定中、状中、述补等基本的结构类型。句法结构具有层次嵌套递归的特点,同时也有对语序的要求,即句法二叉树中的左右节点的位置并不是任意的。这种分析方法语言学上被称为层次分析法,如果我们用该方法分析句子“文程同学热爱编程”,传统图示和句法树图示分别如下:

2.2 满二叉树与完全二叉树

二叉树中有两个特殊的结构类型:满二叉树完全二叉树。满二叉树的结构特点是除了最后一层外,所有层级的节点都有两个子节点;完全二叉树的结构特点是除了最后两层外,所有层级的节点都有两个子节点,倒数第二层的子节点(即最后一层节点)全部靠左排列。如下图所示:

由此可见,满二叉树一定是完全二叉树,完全二叉树可满可不满。这两种二叉树体现了我们采用树状结构存储数据时,对于空间利用率的追求。比如我们设计一个深度为n的二叉树,那么整个二叉树能容纳的最大节点数为2^n-1,满二叉树就是达到了最大节点数,用足了二叉树的容量。完全二叉树除了n层没有子节点,除n-1层外各层父节点都充分利用了自己拥有子节点的名额,也算是尽可能做到了对空间的充分利用。

为了更好地理解完全二叉树的空间利用率,我们看一个非完全二叉树的例子,如下图所示:

上图是一个深度为4的非完全二叉树,前3层的父节点都预留了左右两个子节点的位置,然而第二层的第2个结点只使用了右子节点的空间,浪费了左子节点的空间。如果二叉树的深度很深,其中很多层级的父节点都存在浪费子节点“名额”的现象,那么会造成相当大的空间资源的浪费,二叉树也失去了“二叉”的意义。但是完全二叉树最多浪费倒数第二层父节点的子节点名额, 整体上能够保证较高的空间利用率。

2.3 二叉树的三种遍历方式

二叉树的形状整体上构成一个三角形,最小的二叉树由一个位于中间的父节点和位于左右两侧的子节点构成,这导致遍历访问一棵二叉树的所有节点有三种顺序:前序遍历(Preorder Traversal , VLR)、中序遍历(Inorder Traversal , LDR)和后序遍历(Inorder Traversal , LRD)。

无论哪种遍历方式,二叉树都是从上到下、从左到右遍历的,即从父节点层到子节点层、从左子树到右子树。2.1解释了二叉树的递归性,遍历二叉树时采用的也是递归(recursion)的方式。对于整棵树或某一子树,都是从根开始,先遍历其左子树,再遍历其右子树;分别遍历左右子树时,同样是从根开始,从左向右遍历;以此类推,直到遍历到最后一个右子节点。

如果我们以打印节点数据的方式来表示对节点的访问,那么前序、中序和后序的区别就在于打印节点的时机不同。前序遍历的操作顺序是打印节点在遍历左子树和遍历右子树之前中序遍历的操作顺序是打印节点在遍历左子树和遍历右子树之间后序遍历的操作顺序是打印节点在遍历左子树和遍历右子树之后。子树遍历的过程是递归实现的。

如果我们想遍历2.1演示的“文程同学热爱编程”的句法二叉树,那么用三种遍历方法得到的遍历结果分别如下:

3 二叉树及其遍历的简单实现(Java)

我们用Java语言实现“文程同学热爱编程”这个句子对应的句法二叉树,设计思路是:将同层级的父节点(二叉树及其各子树的根节点)存入数组中,数组中存入的是结点,包括数据左右指针,左右指针分别指向位于下一层节点的左右子节点,如果没有子节点则指针为空指针。

用数组的好处是,可以通过节点所在的索引建立上下层级父节点和子节点的指针联系。假设父节点在它所在的层级数组中的索引为i,那么左子节点在它所在层级数组中的索引为(i+1)*2-2,右子节点的索引为(i+1)*2-1,即左子节点的索引+1。

遍历默认从整棵二叉树的根节点开始,通过方法的重写实现默认参数的效果。

准备工作1:MyBinaryTree.java,创建一个二叉树的类

package com.notes.data_structure6;import com.notes.data_structure6.NumberOfNodesException;public class MyBinaryTree {// 树的根结点private Node[] root;// 树的深度(当前层级数)private int depth;// 将每一层所有的 结点 都存储在数组中,结点数是 2的 层数 次幂private Node[] currentLevel;public MyBinaryTree(String data) {Node[] rootArray = new Node[] {new Node(data)};this.root = rootArray;this.currentLevel = rootArray;}// 定义一个结点类private class Node{private String data; // 数据private Node leftNext; // 左指针private Node rightNext; // 右指针// 构造方法:Node实例化时传入数据public Node(String data) {this.data = data;} }// 向树中增加一层结点public void add(String[] datas) throws NumberOfNodesException {// 层级数增加1depth++;// 新增 层级 的最大结点数int nodeNum = numberOfNextNodes();// 如果传入的 数据数 与 当前层级 最大结点数 不符,抛出异常if(datas.length != nodeNum) {throw new NumberOfNodesException("第"+depth+"层最大父节点数为"+nodeNum);}// 将传入的 数据数组 转换为 结点数组Node[] newLevel = new Node[nodeNum];// 当前 层级的 结点数量(新增层级的父)int nodeNum2 = (int) Math.pow(2, depth-1);// 让每一个结点都与上层 父结点 建立连接for(int i=0;i<nodeNum2;i++) {// 让父结点 的左指针 指向 左子结点int leftIndex = (i+1)*2-2; // 计算左子结点对应的新层级数组的索引currentLevel[i].leftNext = new Node(datas[leftIndex]); // 建立指针指向newLevel[leftIndex] = currentLevel[i].leftNext; // 将结点加入新层级结点数组// 让父结点 的右指针 指向 右子结点int rightIndex = leftIndex+1; // 计算右子结点对应的新层级数组的索引currentLevel[i].rightNext = new Node(datas[rightIndex]); // 建立指针指向newLevel[rightIndex] = currentLevel[i].rightNext; // 将结点加入新层级结点数组}// 让新增层级的数组成为当前层级的数组currentLevel =  newLevel;}// 前序遍历所有结点public void preTraversal(Node node) {if(node==null) {return;}System.out.print(node.data+" ");preTraversal(node.leftNext);preTraversal(node.rightNext);}// 重写 前序遍历 方法,让遍历从 根结点 开始public void preTraversal() {Node node = root[0];if(node==null) {return;}// 递归时调用带参数的方法System.out.print(node.data+" ");preTraversal(node.leftNext);preTraversal(node.rightNext);}// 中序遍历所有结点public void midTraversal(Node node) {if(node==null) {return;}midTraversal(node.leftNext);System.out.print(node.data+" ");midTraversal(node.rightNext);}// 重写中序遍历 方法,让遍历从 根结点 开始public void midTraversal() {Node node = root[0];if(node==null) {return;}// 递归时调用带参数的方法midTraversal(node.leftNext);System.out.print(node.data+" ");midTraversal(node.rightNext);}// 后序遍历所有结点public void posTraversal(Node node) {if(node==null) {return;}posTraversal(node.leftNext);posTraversal(node.rightNext);System.out.print(node.data+" ");}// 重写后序遍历 方法,让遍历从 根结点 开始public void posTraversal() {Node node = root[0];if(node==null) {return;}// 递归时调用带参数的方法posTraversal(node.leftNext);posTraversal(node.rightNext);System.out.print(node.data+" ");}// 查看 新增层级 的最大结点数public int numberOfNextNodes() {return (int) Math.pow(2,depth);}// 查看 树 的深度(层级数)public int getDepth() {return depth;}}

准备工作2:NumberOfNodesException.java,为add()方法创建一个自定义异常,如果传入的数据数与当前层级最大结点数不符,则抛出该异常(如果二叉树不满,在数组的相应位置传入null)。

package com.notes.data_structure6;public class NumberOfNodesException extends Exception{public NumberOfNodesException(String message) {super(message);}
}

句法二叉树的实现及其遍历:TreeDemo.java

package com.notes.data_structure6;public class TreeDemo {public static void main(String[] args) throws NumberOfNodesException {// 实例化二叉树类,并且传入根节点的数据MyBinaryTree tree = new MyBinaryTree("句子");// 加入第一层节点的数据tree.add(new String[] {"主语","谓语"});// 加入第二层节点的数据tree.add(new String[] {"定语","中心语","述语","宾语"});// 前序遍历tree.preTraversal(); // 句子 主语 定语 中心语 谓语 述语 宾语 System.out.println();// 中序遍历tree.midTraversal(); // 定语 主语 中心语 句子 述语 谓语 宾语 System.out.println();// 后序遍历tree.posTraversal(); // 定语 中心语 主语 述语 宾语 谓语 句子 }
}

数据结构学习笔记(六):二叉树(Binary Tree)相关推荐

  1. 【数据结构】二叉树 (Binary Tree)

    目录 一. 什么是树? 二. 二叉树 特殊二叉树 二叉树的性质 二叉树的存储 二叉树的遍历 二叉树的基本操作 一.什么是树? 之前咱们学习了一些简单的数据结构,如顺序表,链表,这些都是线性结构,线性结 ...

  2. 『数据结构与算法』解读树(Tree)和二叉树(Binary Tree)!

    『数据结构与算法』解读树(Tree)和二叉树(Binary Tree)! 文章目录 一. 树 1.1. 树的定义 1.2. 树的基本术语 1.3. 树的性质 二. 二叉树 2.1. 二叉树的定义 2. ...

  3. 数据结构学习笔记(王道)

    数据结构学习笔记(王道) PS:本文章部分内容参考自王道考研数据结构笔记 文章目录 数据结构学习笔记(王道) 一.绪论 1.1. 数据结构 1.2. 算法 1.2.1. 算法的基本概念 1.2.2. ...

  4. 数据结构学习笔记(3-5):树

    附录:所有blog的链接 数据结构学习笔记(1):基本概念 数据结构学习笔记(2):线性结构 数据结构学习笔记(3-5):树 数据结构学习笔记(6-8):图 数据结构学习笔记(9-10):排序 数据结 ...

  5. 数据结构 - 学习笔记 - 红黑树

    数据结构 - 学习笔记 - 红黑树 定义 简介 知识点 1. 结点属性 2. 前驱.后继 3. 旋转 查找 插入 父结点为黑色 父结点为红色 1. 有4种情形只需要变色(对应234树4结点) 1.1. ...

  6. 考研[*数据结构*]学习笔记汇总(全)

    文章目录: 一:预备阶段 二:基础阶段笔记 三:冲刺阶段笔记 四:各章节思维导图 五:题库 来源:王道计算机考研 数据结构 一:预备阶段 之前的数据结构笔记 数据结构--学习笔记--入门必看[建议收藏 ...

  7. 数据结构学习笔记(七):哈希表(Hash Table)

    目录 1 哈希表的含义与结构特点 1.1 哈希(Hash)即无序 1.2 从数组看哈希表的结构特点 2 哈希函数(Hash Function)与哈希冲突(Hash Collision) 2.1 哈希函 ...

  8. 数据结构学习笔记——顺序表的基本操作(超详细最终版+++)建议反复看看ヾ(≧▽≦*)o

    目录 前言 一.顺序表的定义 二.顺序表的初始化 三.顺序表的建立 四.顺序表的输出 五.顺序表的逆序输出 六.顺序表的插入操作 七.顺序表的删除操作 八.顺序表的按位和按值查找 基本操作的完整代码 ...

  9. Python数据结构学习笔记——队列和双端队列

    目录 一.队列的定义 二.队列 实现步骤分析 三.队列的Python实现代码 四.队列的应用 六人传土豆游戏 五.双端队列的定义 六.双端队列 实现步骤分析 七.双端队列的Python实现代码 八.双 ...

最新文章

  1. 16项不可抗拒的云创新
  2. 一文读懂常用开源许可证
  3. dmn是大脑中哪个区域_DMN中的函数式编程:感觉就像再次重读我的大学课程一样...
  4. iis启动时发生意外错误0x8ffe274的解决方法
  5. 删除linux系统中的eth0.bak与多余的网卡
  6. html图片上下高度不一样,【已解决】HTML图片横向布局中第一张图片和其他图片高度不一致...
  7. java.lang.NumberFormatException: For input string:
  8. 研究方法、技术路线、实验手段、关键技术区别和联系
  9. Phaser3之 load
  10. ES 中时间日期类型 “yyyy-MM-dd HH:mm:ss” 的完全避坑指南
  11. 程序设计的三种基本结构
  12. 盛世昊通微达国际联合出品《天下无拐》,还孩子们一片蓝天
  13. 字符串匹配KMP算法讲解
  14. 今天分享的Java开源游戏项目是桌球游戏,初学者也可以用来练习喔~
  15. AirDisk产品怎么恢复出厂设置?
  16. 【Echarts图例点击事件】自定义Echarts图例legend点击事件(已解决)
  17. windows常用操作命令
  18. 一起自学SLAM算法:8.3 LOAM算法
  19. “元宇宙”到底是个啥?鼓励探索,警惕忽悠
  20. 【OpenFOAM】-olaFlow-算例8-setOlaFlume

热门文章

  1. label文字颜色_HowTo —— SwiftUI2.0如何使用Label
  2. 您没有足够的全新为该计算机所有用户安装,很抱歉,无法安装Office(64位),因为您的计算机上已经安装了这些32位Office程序解决办法...
  3. python变量如何使用,python如何使用变量
  4. c mssql mysql_mssql与mysql 数据迁移
  5. Coins and Queries(map迭代器+贪心)
  6. 解除被DenyHosts锁定的IP地址
  7. TreeView控件之,后台构建TreeView(WinForm小程序)
  8. 《浪潮之巅》--百年帝国读后感
  9. Codeforces Round #133 (Div. 2) C. Hiring Staff 想法题目
  10. javaweb jsp