zoukankan      html  css  js  c++  java
  • 日常学习随笔-用链表的形式实现普通二叉树的新增、查找、遍历(前、中、后序)等基础功能(侧重源码+说明)

    一、二叉树

    1、二叉树的概念

    二叉树是每个节点最多有两个子树的树结构。通常子树被称作“左子树”(left subtree)和“右子树”(right subtree),其次序不能任意颠倒。

    2、性质

    (1)若二叉树的层次从0开始,则在二叉树的第i层至多有2^i个结点(i>=0);

    (2)高度为k的二叉树最多有2^(k+1) - 1个结点(k>=-1)。 (空树的高度为-1);

    (3)对任何一棵二叉树,如果其叶子结点(度为0)数为m, 度为2的结点数为n, 则m = n + 1。

    二、二叉树的几种类型

    这里就不多介绍了,目前的进度了解还不够深入,后续继续逐步研究,下面提供一个其他博主介绍的网址:

    https://www.cnblogs.com/love-yh/p/7423301.html

    三、给出一个自定义的二叉树的案例(普通二叉树)

    二叉树类:MyTreeDefin.java

      1 package com.xfwl.algorithmAnalysis.trees;
      2 /**
      3  * 二叉树结构分析
      4  * @function  日常学习测试
      5  * @author 小风微凉
      6  * @time  2018-5-20 下午12:28:50
      7  */
      8 public class MyTreeDefin<T extends Comparable<? super T>>{
      9     /**
     10      * 每棵树都有一个根节点
     11      */
     12     private BinaryNode<T> root;
     13     /**
     14      * 整棵树的节点个数
     15      */
     16     private int nodeCount;
     17     /**
     18      * 二叉树构造器
     19      */
     20     public MyTreeDefin(){
     21         this.reset();
     22     }
     23     /**
     24      * 重置整棵树的结构
     25      */
     26     private void reset(){
     27         //二叉树的根节点初始化
     28         root=null;
     29         //二叉树的节点总数:归0
     30         this.nodeCount=0;
     31     }
     32     /**
     33      * 清空整棵二叉树
     34      * @return
     35      */
     36     public boolean makeEmpty(){
     37         this.reset();
     38         return this.isEmpty();
     39     }
     40     /**
     41      * 获取树的节点个数
     42      * @return
     43      */
     44     public int getSize(){
     45         return this.nodeCount;
     46     }
     47     /**
     48      * 判断整棵树是否为空树
     49      * @return
     50      */
     51     public boolean isEmpty(){
     52         return this.nodeCount==0?true:false;
     53     }
     54     /**
     55      * 判断二叉树中指定节点后面是否包含指定数据
     56      * @param target  检索数据target
     57      * @param node    指定的节点(包含当前节点)
     58      * @return
     59      */
     60     public boolean contains(T target,BinaryNode<T> node){
     61         //判空检查
     62         if(node==null){
     63             return false;
     64         }
     65         //先和当前节点的数据比较
     66         int compareResult=target.compareTo(node.elem);
     67         if(compareResult>0){//进入右子树中继续判断
     68             return contains(target,node.right);
     69         }else if(compareResult<0){//进入左子树中继续判断
     70             return contains(target,node.left);
     71         }else{//相等
     72             return true;
     73         }
     74     }
     75     /**
     76      * 从根节点开始查找整棵树是否包含指定的数据
     77      * @param target 检索数据target
     78      * @return
     79      */
     80     public boolean contains(T target){
     81         return this.contains(target, this.root);
     82     }
     83     /**
     84      * 查找整棵树中的最小数据
     85      * 左子树最后一个节点数据
     86      * @return
     87      */
     88     public T findMin(){
     89         return this.findMin(this.root).elem;
     90     }
     91     /**
     92      * 查找指定树节点下面的最小节点[查找指定节点后面的最小节点]
     93      * @param node    指定的节点
     94      * @return
     95      */
     96     public BinaryNode<T> findMin(BinaryNode<T> node){
     97         //如果节点为空
     98         if(node==null){
     99             return null;
    100         }else if(node.left==null){//递归基准情况
    101             return node;
    102         }else{//递归流程
    103             return findMin(node.left);
    104         }
    105     }
    106     /**
    107      * 查找指定树节点下面的最大节点[最大的数据在右子树的最深叶子节点]
    108      * @param node   指定的查找起点节点
    109      * @return
    110      */
    111     public BinaryNode<T> findMax(BinaryNode<T> node){
    112         //如果节点为空
    113         if(node==null){
    114             return null;
    115         }else if(node.right==null){//递归基准情况
    116             return node;
    117         }else{//递归流程
    118             return findMax(node.right);
    119         }
    120     }
    121     /**
    122      * 查找整棵树中的最大数据
    123      * @return
    124      */
    125     public T findMax(){        
    126         return this.findMax(this.root).elem;
    127     }
    128     /**
    129      * 为二叉树添加新的节点(对外)
    130      * @param data 要添加的数据
    131      * @return
    132      */
    133     public BinaryNode<T> add(T data){
    134         if(this.isEmpty()){
    135             this.nodeCount++;
    136             this.root=new BinaryNode<>(data,null,null);
    137             return this.root;
    138         }else{
    139             this.nodeCount++;
    140             return this.add(data, this.root);
    141         }        
    142     }
    143     /**
    144      * 为二叉树添加新的节点(对内)
    145      * @param data 要添加的数据
    146      * @param curNode 要添加的节点(递归比较)
    147      */
    148     private BinaryNode<T> add(T data,BinaryNode<T> curNode){
    149         //如果节点不存在:递归基准情况
    150         if(curNode==null){
    151             return new BinaryNode<>(data,null,null);
    152         }
    153         //按照:左>根>右  的大小顺序插入二叉树中
    154         //比较起点:先和根节点数据比较
    155         int compareResult=data.compareTo(curNode.elem);
    156         if(compareResult<0){//走左子树
    157             System.out.println("左<--");
    158             curNode.left=this.add(data,curNode.left);
    159         }else if(compareResult>0){//走右子树
    160             System.out.println("-->右");
    161             curNode.right=this.add(data,curNode.right);
    162         }else{//如果添加的节点数据和当前比较的根节点相同
    163             //不做任何处理,可在此继续扩展
    164         }                
    165         //返回的是根节点
    166         return curNode;
    167     }
    168     /**
    169      * 非递归添加树节点
    170      * @param data 节点数据
    171      * @return
    172      */
    173     public void  push(T data){
    174         if(this.isEmpty()){//空树结构
    175             this.nodeCount++;
    176             this.root=new BinaryNode<>(data,null,null);
    177         }else{//至少含有一个根节点
    178             BinaryNode<T> tmpNode =this.root;
    179             System.out.println("--------------------根节点数据:"+tmpNode.elem+",--------------------");
    180             while(true){
    181                 System.out.println("while----:tmpNode.elem="+tmpNode.elem+",data="+data);
    182                 int compareResult=data.compareTo(tmpNode.elem);
    183                 if(compareResult<0){//走左子树
    184                     System.out.println("左<--");
    185                     if(tmpNode.left==null){
    186                         tmpNode.left=new BinaryNode<>(data,null,null);
    187                         break;
    188                     }
    189                     tmpNode=tmpNode.left;
    190                 }else if(compareResult>0){//走右子树
    191                     System.out.println("-->右");
    192                     if(tmpNode.right==null){
    193                         tmpNode.right=new BinaryNode<>(data,null,null);
    194                         break;
    195                     }
    196                     tmpNode=tmpNode.right;
    197                 }else{//替换当前节点数据(压入相同数据,没改变)
    198                     //也即不做处理
    199                     break;
    200                 }
    201             }
    202             this.nodeCount++;
    203         }
    204     }
    205     /**
    206      * 移除二叉树中根节点后面的指定数据(所在的节点)
    207      * @param data  指定的数据
    208      */
    209     public BinaryNode<T> remove(T data){
    210         return this.remove(data, this.root);
    211     }
    212     /**
    213      * [删除是最难的:慢慢琢磨-琢磨好了-以后另开一篇]
    214      * 移除二叉树中指定节点后面的指定数据(所在的节点)
    215      * @param node  指定的节点
    216      * @param data  指定的数据
    217      */
    218     public BinaryNode<T> remove(T data,BinaryNode<T> node){
    219         //节点判断
    220         if(node==null){
    221             return null;
    222         }
    223         //开始比较
    224         int compareResult=data.compareTo(node.elem);
    225         if(compareResult==0){//找到基准情况[刚好找到要删除的数据节点]
    226             /**
    227              * 找到这个节点
    228              */
    229         }
    230         //....算了,考虑的头比较痛,下次再开一篇专门研究二叉树删除的案例
    231         return null;
    232     }
    233     /**
    234      * 打印树结构信息
    235      * @param index  遍历的类型
    236      * 一般用到的遍历方式有三种:
    237      * (1)前序遍历    0
    238      * (2)中序遍历    1
    239      * (3)后序遍历    2
    240      */
    241     public void printTree(int index){
    242         String type=(index==0?"前序":index==1?"中序":"后序")+"遍历";
    243         System.out.println("------------【开始遍历打印·"+type+"】------------");
    244         switch(index){
    245             case 0:preOrder(this.root);break;
    246             case 1:inOrder(this.root);break;
    247             case 2:postOrder(this.root);break;
    248         } 
    249         System.out.println("------------【打印结束】------------");        
    250     }
    251     /**
    252      * 前序遍历
    253      * @param node  遍历的起始节点
    254      * 采用递归思想
    255      *  对左子节点进行遍历
    256      *  对右子节点进行遍历
    257      *  递归基值是node是否是null
    258      */
    259      private void preOrder(BinaryNode<T> node)
    260      {
    261         if(node==null){
    262             return;
    263         }else{
    264             System.out.print(node.elem+" ");//输出数据节点信息
    265             preOrder(node.left);
    266             preOrder(node.right);
    267         }
    268      }
    269     /**
    270      * 中序遍历
    271      * @param node
    272      */
    273     private void inOrder(BinaryNode<T> node){
    274         if(node==null){
    275             return;
    276         }else{
    277             inOrder(node.left);
    278             System.out.print(node.elem+" ");
    279             inOrder(node.right);
    280         }
    281     }
    282     /**
    283      * 后序遍历
    284      * @param node
    285      */
    286     private void postOrder(BinaryNode<T> node){
    287         if(node==null){
    288             return;
    289         }else{
    290             postOrder(node.left);
    291             postOrder(node.right);
    292             System.out.print(node.elem+" ");
    293         }
    294     }
    295     /**
    296      * 获取指定节点的数据
    297      * @param node
    298      * @return
    299      */
    300     public T getElem(BinaryNode<T> node){
    301         if(node==null){
    302             return null;
    303         }
    304         return node.elem;
    305     }
    306     /**
    307      * 内置一个树节点类
    308      */
    309     private static class BinaryNode<T>{
    310         /**
    311          * 树节点存放数据域
    312          */
    313         T elem;
    314         /**
    315          * 左子树节点域
    316          */
    317         BinaryNode<T> left;
    318         /**
    319          * 右子树节点域
    320          */
    321         BinaryNode<T> right;
    322         /**
    323          * 构造器
    324          */
    325         public BinaryNode(T elem,BinaryNode<T> left,BinaryNode<T> right){
    326             this.elem=elem;
    327             this.left=left;
    328             this.right=right;
    329         }        
    330     }
    331 }
    332  

    测试类:Test.java

     1 package com.xfwl.algorithmAnalysis.trees;
     2 
     3 public class Test {
     4     /**
     5      * @param args
     6      */
     7     public static void main(String[] args) {
     8         //创建一棵树
     9         MyTreeDefin<Integer> tree=new MyTreeDefin<>();
    10         //压入数据
    11         tree.push(5);
    12         tree.push(2);
    13         tree.push(4);
    14         tree.push(8);
    15         tree.push(7);
    16         tree.push(10);
    17         tree.push(3);
    18         tree.push(9);
    19         tree.push(6);
    20         tree.push(1);
    21         System.out.println(tree.getSize());
    22         //开始遍历显示
    23         tree.printTree(0);
    24         tree.printTree(1);
    25         tree.printTree(2);
    26         //删除
    27     }
    28 }

    测试结果:

    --------------------根节点数据:5,--------------------
    while----:tmpNode.elem=5,data=2<--
    --------------------根节点数据:5,--------------------
    while----:tmpNode.elem=5,data=4<--
    while----:tmpNode.elem=2,data=4
    -->--------------------根节点数据:5,--------------------
    while----:tmpNode.elem=5,data=8
    -->--------------------根节点数据:5,--------------------
    while----:tmpNode.elem=5,data=7
    -->while----:tmpNode.elem=8,data=7<--
    --------------------根节点数据:5,--------------------
    while----:tmpNode.elem=5,data=10
    -->while----:tmpNode.elem=8,data=10
    -->--------------------根节点数据:5,--------------------
    while----:tmpNode.elem=5,data=3<--
    while----:tmpNode.elem=2,data=3
    -->while----:tmpNode.elem=4,data=3<--
    --------------------根节点数据:5,--------------------
    while----:tmpNode.elem=5,data=9
    -->while----:tmpNode.elem=8,data=9
    -->while----:tmpNode.elem=10,data=9<--
    --------------------根节点数据:5,--------------------
    while----:tmpNode.elem=5,data=6
    -->while----:tmpNode.elem=8,data=6<--
    while----:tmpNode.elem=7,data=6<--
    --------------------根节点数据:5,--------------------
    while----:tmpNode.elem=5,data=1<--
    while----:tmpNode.elem=2,data=1<--
    10
    ------------【开始遍历打印·前序遍历】------------
    5 2 1 4 3 8 7 6 10 9 ------------【打印结束】------------
    ------------【开始遍历打印·中序遍历】------------
    1 2 3 4 5 6 7 8 9 10 ------------【打印结束】------------
    ------------【开始遍历打印·后序遍历】------------
    1 3 4 2 6 7 9 10 8 5 ------------【打印结束】------------

    四、总结一下

      最近比较忙,学习进度明显感到有点延迟了,还是得抓紧时间啊!上面的测试例子并没有写“二叉树的删除”功能,删除也比较麻烦,分为很多种情形,需要仔细分析,此篇就不在分析说明了,以后再慢慢研究,要学的东西还很多,慢慢来吧!

  • 相关阅读:
    Leetcode 92. Reverse Linked List II
    Leetcode 206. Reverse Linked List
    Leetcode 763. Partition Labels
    Leetcode 746. Min Cost Climbing Stairs
    Leetcode 759. Employee Free Time
    Leetcode 763. Partition Labels
    搭建数据仓库第09篇:物理建模
    Python进阶篇:Socket多线程
    Python进阶篇:文件系统的操作
    搭建数据仓库第08篇:逻辑建模–5–维度建模核心之一致性维度2
  • 原文地址:https://www.cnblogs.com/newwind/p/9094937.html
Copyright © 2011-2022 走看看