• 数据结构与算法——16.二叉树


    这篇文章我们来讲一下二叉树

    目录

    1.概述

    2.代码实现

    1.概述

    树:(Tree)是计算机数据存储的一种结构,因为存储类型和现实生活中的树类似所以被称为树。

    树的源头被称为,树其余分叉点被称为节点,而树这种数据结构的起始分叉点被称为根节点。树衍生的尽头就是叶,在树这种数据结构中把叶称之为叶节点

    树中每一节点的起源点被称为父节点,衍生出去的点被称为子节点。没有父节点的就是根节点,没有子节点的就是叶节点,而同一父节点的就是兄弟节点

    树的基础概念:

    高度,是从下往上看,用来表示从根节点到最顶端叶节点所需要遍历的节点数 (包括叶节点)

    深度与高度相反,是从上往下看,用来表示 从最顶端叶节点到根节点所需要遍历的节点数(包括根节点)。层数,即 高度 +1

    二叉树:是最常用的树形结构,每个结点最多能够有两个子节点

    完全二叉树:上层全部填满,并且最后一层按从左到右的顺序来填充。(前面讲的堆就是一个完全二叉树)

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

    二叉查找树:所有的左节点值都小于父节点值,所有的右节点值都大于父节点值的二叉树。

    注意:这里要注意完全二叉树和满二叉树的区别。

    二叉树的实现方式有数组和链表两种实现方式。

    下面看一下二叉树的遍历

    遍历:即把二叉树的每一个节点都访问一遍。遍历有两种方式,即广度优先和深度优先,其中深度优先又分前序,中序和后序三种,下面来详细的看一下。

    广度优先遍历:尽可能的先访问距离根节点最近的节点,也称为层序遍历

    深度优先遍历:对于二叉树,深度优先遍历可以分为三种(要深入到叶子节点):

    • 前序遍历:对于每一颗子树,先访问该节点,然后是左子树,最后是右子树
    • 中序遍历:对于每一颗子树,先访问左子树,然后是该节点,最后是右子树
    • 后序遍历:对于每一颗子树,先访问左子树,然后是右子树,最后是该节点

    下面用具体的实例来看一下二叉树的几种遍历方式:

    解析:

    广度优先,不解释了

    前序遍历:前序遍历的定义是先访问该节点,然后是左子树,然后是右子树。就上图来说,首先是根节点即1,然后是左子树,即2这边,在这个子树上面依然按照上面的规则走,所以先是2,然后访问2的左子树,然后是右子树。然后又回到上面的根节点处,现在1的左子树访问完了,然后就访问1的右子树,右子树的访问规则和上面的是一样的。

    中序遍历:中序遍历的定义是先访问左子树,然后是根节点,然后是右子树。依然拿上图来说,先访问左子树,即2那部分,然后看2有没有左子树,有,那就访问2的左子树,即4,然后是2,然后是2的右子树,2的那颗树访问完了,就回到根节点,即1,然后再访问1的右子树,逻辑和上面是一样的。这就是中序遍历。

    后序遍历:后序遍历的定义是先访问左子树,然后是右子树,然后是根节点。拿上图来说,先访问1的左子树,到达了2后,先访问2的左子树,访问完再访问2的右子树,然后是2,然后回到1处,1的左子树访问完了,然后接着访问1的右子树,等右子树访问完后,最后访问根节点1.

    2.代码实现

    下面用代码来实现一下树的相关操作:

    节点类如下:

    下面看一下代码:

    1. package Tree;
    2. import java.util.LinkedList;
    3. /**普通的二叉树的三种深度优先遍历*/
    4. public class L1_Tree {
    5. public static void main(String[] args) {
    6. /*树的构造*/
    7. L1_TreeNode root = new L1_TreeNode(
    8. new L1_TreeNode(new L1_TreeNode(4),2,null),
    9. 1,
    10. new L1_TreeNode(new L1_TreeNode(5),3,new L1_TreeNode(6))
    11. );
    12. postOrder2(root);
    13. }
    14. public static void preOrder1(L1_TreeNode node){
    15. if (node == null){return;}
    16. System.out.print(node.value+" ");
    17. preOrder1(node.leftTreeNode);
    18. preOrder1(node.rightTreeNode);
    19. }
    20. public static void inOrder1(L1_TreeNode node){
    21. if (node == null){return;}
    22. inOrder1(node.leftTreeNode);
    23. System.out.println(node.value+" ");
    24. inOrder1(node.rightTreeNode);
    25. }
    26. public static void postOrder1(L1_TreeNode node){
    27. if (node == null){return;}
    28. postOrder1(node.leftTreeNode);
    29. postOrder1(node.rightTreeNode);
    30. System.out.println(node.value+" ");
    31. }
    32. public static void preOrder2(L1_TreeNode node){
    33. LinkedList stack = new LinkedList<>();
    34. L1_TreeNode current = node;//代表当前节点
    35. while (current != null || !stack.isEmpty()){
    36. if (current!=null){
    37. System.out.println("去:"+current.value);
    38. stack.push(current);//压入栈,通过栈记住回来的路
    39. current = current.leftTreeNode;
    40. }else {
    41. L1_TreeNode pop = stack.pop();
    42. //System.out.println("回:"+pop.value);
    43. current = pop.rightTreeNode;
    44. }
    45. }
    46. }
    47. public static void inOrder2(L1_TreeNode node){
    48. LinkedList stack = new LinkedList<>();
    49. L1_TreeNode current = node;//代表当前节点
    50. while (current != null || !stack.isEmpty()){
    51. if (current!=null){
    52. //System.out.println("去:"+current.value);
    53. stack.push(current);//压入栈,通过栈记住回来的路
    54. current = current.leftTreeNode;
    55. }else {
    56. L1_TreeNode pop = stack.pop();
    57. System.out.println("回:"+pop.value);
    58. current = pop.rightTreeNode;
    59. }
    60. }
    61. }
    62. public static void postOrder2(L1_TreeNode node){
    63. LinkedList stack = new LinkedList<>();
    64. L1_TreeNode current = node;//代表当前节点
    65. L1_TreeNode pop = null;//最近一次弹栈的元素
    66. while (current != null || !stack.isEmpty()){
    67. if (current!=null){
    68. //System.out.println("去:"+current.value);
    69. stack.push(current);//压入栈,通过栈记住回来的路
    70. current = current.leftTreeNode;
    71. }else {
    72. L1_TreeNode peek = stack.peek();
    73. if (peek.rightTreeNode == null || peek.rightTreeNode == pop){
    74. pop = stack.pop();
    75. System.out.println("回:"+pop.value);
    76. }else {
    77. current = peek.rightTreeNode;
    78. }
    79. }
    80. }
    81. }
    82. //一套代码完成二叉树的三种深度优先遍历
    83. public static void Order(L1_TreeNode node){
    84. LinkedList stack = new LinkedList<>();
    85. L1_TreeNode current = node;//代表当前节点
    86. L1_TreeNode pop = null;//最近一次弹栈的元素
    87. /**
    88. *前序:值左右
    89. *中序:左值右
    90. *后序:左右值
    91. * */
    92. while (current != null || !stack.isEmpty()){
    93. if (current!=null){
    94. stack.push(current);//压入栈,通过栈记住回来的路
    95. //sout(value)前序
    96. current = current.leftTreeNode;//处理左子树
    97. }else {
    98. L1_TreeNode peek = stack.peek();
    99. if (peek.rightTreeNode == null ){//没有右子树
    100. //sout(value)中序
    101. pop = stack.pop();
    102. //sout(value)后序
    103. }
    104. else if (peek.rightTreeNode == pop){//右子树处理完成
    105. pop = stack.pop();
    106. //sout(value)后序
    107. }
    108. else {
    109. //sout(value)中序
    110. current = peek.rightTreeNode;//处理右子树
    111. }
    112. }
    113. }
    114. }
    115. }

    递归的很简单

    主要就是要了解非递归的解决方案。

  • 相关阅读:
    uniapp开发微信小程序运行报错不知道是哪里有问题,求帮看看
    Java版本+企业电子招投标系统源代码+支持二开+招投标系统+中小型企业采购供应商招投标平台
    【Spring面试】十、SpringBoot相关
    基于uni-app的动态表单
    【解决方案】Java 互联网项目中消息通知系统的设计与实现(上)
    提供CY系列菁染料CY3、CY5、CY5.5、CY7、CY7.5,ICG,荧光素FITC,Bodipy系列染料标记海藻酸钠Alginate
    如何设计出优秀的虚拟展厅,设计虚拟展厅有哪些步骤
    【跨域问题】
    kotlin基础教程:<3>函数的高级用法和字符串的基础操作
    基本的Linux命令
  • 原文地址:https://blog.csdn.net/m0_52096593/article/details/133208835