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

一、二叉树

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 ------------【打印结束】------------

四、总结一下

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

原文地址:https://www.cnblogs.com/newwind/p/9094937.html