Java数据结构与算法学习笔记--二叉树

  1 package com.tree;
  2 
  3 /*
  4  *     为什么需要树这种数据结构
  5  *         1)数组存储方式的分析:
  6  *             优点:通过下标方式访问元素,速度快,对于有序数组,还可以使用二分查找提高检索速度
  7  *             缺点:如果检索具体某个值,或者插入值(按一定顺序)会整体一定,效率非常低
  8  *         2)链式存储方式的分析
  9  *             优点:在一定程度上渡数组存储方式有优化(比如:插入一个数值节点,只需要将插入节点,链接到链表中
 10  *                 即可,删除效率也很好
 11  *             缺点:在进行检索时,效率仍然较低,比如(检索某个值,需要从头节点开始遍历);
 12  *         3)树存储方式的分析
 13  *             能提高数据存储、读取的效率,比如利用二叉排序树,既可以保证数据的检索速度,
 14  *             同时也可以保证数据的插入、删除、修改速度
 15  *             下面以[7,3,10,1,5,9,12]用二叉排序树来存储数据,如下,简单演示增删改查效率如何都可以提高
 16  *                             7
 17  *                           /      \
 18  *                         3        10
 19  *                       /      \       /  \
 20  *                     1        5 9        12
 21  *             分析:1、假如现在需要检索12
 22  *                     1)首先12跟7比较,则,12比7大,所以12应该在右子树
 23  *                     2)12继续与10比较,发现比12还大,所以在10的右字树
 24  *                     3)12跟12比较,找到
 25  *                 2、插入一个13
 26  *                     1)首先跟7比较,发现比7大,所以应该在7的右字树上
 27  *                     2)继续跟10比较,发现比10也大,所以应该在10的右字树上
 28  *                     3)继续跟12比较,发现比12还大,所以应该在12的右字树上
 29  *                     4)12的右子数节点为空,所以直接作为12的右子节点插入即可
 30  *                 3、删除的如果是中间节点,则需要做一点点处理,这里暂时不阐述
 31  * 
 32  *     树的常用术语:
 33  *         1、节点:节点对象
 34  *         2、根节点:
 35  *         3、父节点
 36  *         4、子节点
 37  *         5、叶子节点:没有子节点的节点
 38  *         6、节点的权:节点值
 39  *         7、路径:从root节点找到该节点的路线
 40  *         8、层
 41  *         9、子树
 42  *         10、树的高度:最大层数
 43  *         11、森林:多棵子树构成森林
 44  * 
 45  *     二叉树:
 46  *         1、树有很多种,每个节点最多只能有两个子节点的一种形式成为二叉树
 47  *         2、二叉树的子节点分为左子节点和右子节点
 48  *         3、如果该二叉树的所有叶子节点都在最后一层,并且节点总数=2**n-1,n为层数,我们称之为满二叉树
 49  *         4、如果该二叉树的所有叶子节点都在最后一层,或者倒数第二层,而且最后一层的叶子节点在左边连续,
 50  *         在倒数第二层的叶子节点在右边连续,我们称之为完全二叉树
 51  * 
 52  *     二叉树遍历的方式
 53  *         1、前序:先输出父节点,再遍历左子树和右字树
 54  *         2、中序:先遍历左子树,再输出父节点,再遍历右字树
 55  *         3、后序:先遍历左子树,再遍历右字树,最后输出父节点
 56  *         小结:看输出父节点的顺序,就确定是前序、中序还是后序
 57  * 
 58  *     二叉树遍历思路
 59  *         1.创建一棵二叉树,比如
 60  *                             A
 61  *                           /      \
 62  *                         B        C
 63  *                       /      \       /  \
 64  *                     D        E F        G
 65  *         2、前序遍历
 66  *             1)先输出当前节点
 67  *             2)如果左子节点不为空,则递归继续前序遍历
 68  *             3)如果右字节点不为空,则递归继续前序遍历
 69  *         3、中序遍历:
 70  *             1)如果当前节点的左子节点不为空,则递归继续中序遍历
 71  *             2)输出当前节点
 72  *             3)如果当前节点的右子节点不为空,则递归继续中序遍历
 73  *         4、后序遍历:
 74  *             1)如果当前节点的左子节点不为空,则递归继续后序遍历
 75  *             2)如果当前节点的右子节点不为空,则迪拜继续后序遍历
 76  *             3)输出当前节点
 77  * 
 78  *     二叉树-查找指定节点
 79  *         要求:
 80  *             1)请编写前序查找、中序查找和后序查找的方法
 81  *             2)并分别利用三种查找方式,查找heroNo=5的节点
 82  *             3)并分析各种查找方式,分别比较了多少次
 83  *        思路:
 84  *            前序查找思路:
 85  *                1)先判断当前节点的no是否等于要查找的
 86  *                2)如果相等,则返回当前节点
 87  *                3)如果不等,则判断当前节点的左子节点是否为空,如果不为空,则递归前序查找
 88  *                4)如果左递归程序查找,找到节点,则返回,否则继续判断,当前的节点的右子节点是否为空
 89  *                如果不为空,继续向右递归前序查找
 90  *            中序查找思路:
 91  *                1)判断当前节点的左子节点是否为空,如果不为空,则递归中序查找
 92  *                2)如果找到,则返回,如果没有找到,就和当前节点比较,如果是则返回当前节点,
 93  *                否则继续进行递归的中序查找
 94  *                3)如果右递归中序查找,找到则返回,否则返回null
 95  *            后序查找思路:
 96  *                1)判断当前节点的左子节点是否为空,如果不为空,则递归中序查找
 97  *                2)如果找到,就返回,如果没有找到,则判断当前节点的右子节点是否为空,
 98  *                如果不为空,则右递归进行后序查找,如果找到就返回
 99  *                3)如果没找到就和当前节点比较,如果是则返回,否则返回null
100  *             
101  *     二叉树-删除节点
102  *         要求:
103  *             1、如果删除的节点是叶子节点,则删除该节点
104  *             2、如果删除的节点时非叶子节点,则删除该子树(先简单处理,深入处理后序再继续)
105  *             3、测试、删除掉5号叶子节点和2号子树
106  *         思路:
107  *             0、首先:考虑如果树是空树root,如果只有一个root节点,则等价于将二叉树置空
108  *             1、因为我们的二叉树是单向的,所以我们是判断当前节点的子节点是否需要删除,
109  *             而不能取判断当前节点是否需要删除
110  *             2、如果当前节点的左子树不为空,并且左子节点的编号就是需要删除的节点,
111  *             就将this.left置空,并且返回,结束递归删除
112  *             3、如果当期节点的右子节点不为空,并且右子节点就是要删除的节点,就将
113  *             this.right置空,并且返回,并且结束递归删除
114  *             4、如果第2和第3步都没有删除,那么就需要向左字树递归删除
115  *             5、如果第4步也没有删除,则应当向右字树进行递归删除
116  */
117 
118 class HeroNode
119 {
120     private int no;
121     private String name;
122     private HeroNode left;
123     private HeroNode right;
124     
125     HeroNode(int no,String name)
126     {
127         this.no=no;
128         this.name=name;
129     }
130 
131     public int getNo() {
132         return no;
133     }
134 
135     public void setNo(int no) {
136         this.no = no;
137     }
138 
139     public String getName() {
140         return name;
141     }
142 
143     public void setName(String name) {
144         this.name = name;
145     }
146 
147     public HeroNode getLeft() {
148         return left;
149     }
150 
151     public void setLeft(HeroNode left) {
152         this.left = left;
153     }
154 
155     public HeroNode getRight() {
156         return right;
157     }
158 
159     public void setRight(HeroNode right) {
160         this.right = right;
161     }
162 
163     @Override
164     public String toString() {
165         return "HeroNode [no=" + no + ", name=" + name + "]";
166     }
167     
168     //前序遍历的方法
169     public void preOrder()
170     {
171         System.out.println(this);//先输出父节点
172         //向左字树递归
173         if(this.left!=null)
174         {
175             this.left.preOrder();
176         }
177         
178         //向右字树递归
179         if(this.right!=null)
180         {
181             this.right.preOrder();
182         }
183     }
184     //中序遍历的方法
185     public void infixOrder()
186     {
187         //向左子树递归中序遍历
188         if(this.left!=null)
189         {
190             this.left.infixOrder();
191         }
192         //输出父节点
193         System.out.println(this);
194         //向右字树递归中序遍历
195         if(this.right!=null)
196         {
197             this.right.infixOrder();
198         }
199     }
200     //后序遍历的方法
201     public void postOrder()
202     {
203         //向左子树递归后序遍历
204         if(this.left!=null)
205         {
206             this.left.postOrder();
207         }
208         //向右字树递归后序遍历
209         if(this.right!=null)
210         {
211             this.right.postOrder();
212         }
213         //输出当前父节点
214         System.out.println(this);
215     }
216     
217     /**
218      *     前序遍历查找
219      * @param no 查找no
220      * @return 如果找到就返回该Node,如果没找到就返回null
221      */
222     public HeroNode preOrderSearch(int no) {
223         System.out.println("进入前序遍历查找......");
224         if(this.no == no)
225         {
226             
227             return this;
228         }
229         HeroNode resNode=null;
230         if(this.left!=null)
231         {
232             resNode=this.left.preOrderSearch(no);
233         }
234         if(resNode !=null)
235         {
236             //说明左子树找到了
237             return resNode;
238         }
239         if(this.right!=null)
240         {
241             resNode=this.right.preOrderSearch(no);
242         }
243         return resNode;
244     }
245     /**
246      *     中序遍历查找
247      * @param no 查找no
248      * @return 如果找到就返回该Node,如果没找到就返回null
249      */
250     public HeroNode infixOrderSearch(int no)
251     {
252         
253         HeroNode resNode=null;
254         if(this.left!=null)
255         {
256             resNode=this.left.infixOrderSearch(no);
257         }
258         if(resNode!=null)
259         {
260             return resNode;
261         }
262         System.out.println("进入中序遍历查找......");
263         if(this.no==no)
264         {
265             
266             return this;
267         }
268         if(this.right!=null)
269         {
270             resNode=this.right.infixOrderSearch(no);
271         }
272         return resNode;
273     }
274     /**
275      *     后序遍历查找
276      * @param no 查找no
277      * @return 如果找到就返回该Node,如果没找到就返回null
278      */
279     public HeroNode postOrderSearch(int no)
280     {
281         
282         HeroNode resNode=null;
283         if(this.left!=null)
284         {
285             resNode=this.left.postOrderSearch(no);
286         }
287         if(resNode!=null)
288         {
289             return resNode;
290         }
291         if(this.right!=null)
292         {
293             resNode=this.right.postOrderSearch(no);
294         }
295         if(resNode!=null)
296         {
297             return resNode;
298         }
299         System.out.println("进入后序遍历查找......");
300         if(this.no==no)
301         {
302             
303             return this;
304         }
305         else
306         {
307             return null;
308         }
309     }
310     
311     public void delNode(int no)
312     {
313         /*
314          *     思路:
315          * 1、因为我们的二叉树是单向的,所以我们是判断当前节点的子节点是否需要删除,
316          *     而不能取判断当前节点是否需要删除
317          *     2、如果当前节点的左子树不为空,并且左子节点的编号就是需要删除的节点,
318          *     就将this.left置空,并且返回,结束递归删除
319          *     3、如果当期节点的右子节点不为空,并且右子节点就是要删除的节点,就将
320          *     this.right置空,并且返回,并且结束递归删除
321          *     4、如果第2和第3步都没有删除,那么就需要向左字树递归删除
322          *     5、如果第4步也没有删除,则应当向右字树进行递归删除
323          */
324         
325         if(this.left!=null && this.left.no==no)
326         {
327             this.left=null;
328             return;
329         }
330         if(this.right!=null && this.right.no == no)
331         {
332             this.right=null;
333             return;
334         }
335         if(this.left!=null)
336         {
337             this.left.delNode(no);
338         }
339         if(this.right!=null)
340         {
341             this.right.delNode(no);
342         }
343     }
344 }
345 
346 //定义一个BinaryTree
347 class BinaryTree
348 {
349     private HeroNode root;
350 
351     public HeroNode getRoot() {
352         return root;
353     }
354 
355     public void setRoot(HeroNode root) {
356         this.root = root;
357     }
358     
359     public void preOrder()
360     {
361         if(this.root!=null)
362         {
363             this.root.preOrder();
364         }
365         else
366         {
367             System.out.println("当前二叉树为空,无法遍历");
368         }
369     }
370     
371     public void infixOrder()
372     {
373         if(this.root!=null)
374         {
375             this.root.infixOrder();
376         }
377         else
378         {
379             System.out.println("当前二叉树为空,无法遍历");
380         }
381     }
382     
383     public void postOrder()
384     {
385         if(this.root!=null)
386         {
387             this.root.postOrder();
388         }
389         else
390         {
391             System.out.println("当前二叉树为空,无法遍历");
392         }
393     }
394     
395     public HeroNode preOrderSearch(int no)
396     {
397         if(this.root!=null)
398         {
399             return this.root.preOrderSearch(no);
400         }
401         else
402         {
403             return null;
404         }
405     }
406     
407     public HeroNode infixOrderSearch(int no)
408     {
409         if(this.root!=null)
410         {
411             return this.root.infixOrderSearch(no);
412         }
413         else
414         {
415             return null;
416         }
417     }
418     
419     public HeroNode postOrderSearch(int no)
420     {
421         if(this.root!=null)
422         {
423             return this.root.postOrderSearch(no);
424         }
425         else
426         {
427             return null;
428         }
429     }
430     public void delNode(int no)
431     {
432         if(this.root!=null)
433         {
434             if(this.root.getNo()==no)
435             {
436                 this.root=null;
437             }
438             else
439             {
440                 this.root.delNode(no);
441             }
442         }
443         else
444         {
445             System.out.println("这是一棵空树,不能删除......");
446         }
447     }
448 }
449 public class BinaryTreeDemo {
450 
451     public static void main(String[] args) {
452         // TODO Auto-generated method stub
453         BinaryTree bt=new BinaryTree();
454         HeroNode root=new HeroNode(1,"宋江");
455         HeroNode n2=new HeroNode(2,"无用");
456         HeroNode n3=new HeroNode(3,"卢俊义");
457         HeroNode n4=new HeroNode(4,"林冲");
458         HeroNode n5=new HeroNode(5,"关胜");
459         //说明:先手动创建二叉树,后面学习递归的方法创建二叉树
460         root.setLeft(n2);
461         root.setRight(n3);
462         n3.setRight(n4);
463         n3.setLeft(n5);
464         bt.setRoot(root);
465         
466         System.out.println("前序遍历:");
467         bt.preOrder();
468         System.out.println("中序遍历:");
469         bt.infixOrder();
470         System.out.println("后序遍历:");
471         bt.postOrder();
472         
473         System.out.println("前序查找:...");
474         System.out.println("前序查找结果5: "+bt.preOrderSearch(5));
475         System.out.println("中序查找结果5: "+bt.infixOrderSearch(5));
476         System.out.println("中序查找结果5: "+bt.postOrderSearch(5));
477         
478         System.out.println("前序查找结果15: "+bt.preOrderSearch(15));
479         System.out.println("中序查找结果15: "+bt.infixOrderSearch(15));
480         System.out.println("中序查找结果15: "+bt.postOrderSearch(15));
481         
482         System.out.println("测试一下delNode的方法......");
483         System.out.println("删除前的bt:");
484         bt.preOrder();
485         bt.delNode(5);
486         System.out.println("删除后的bt:");
487         bt.preOrder();
488         
489         System.out.println("删除前的bt:");
490         bt.preOrder();
491         bt.delNode(3);
492         System.out.println("删除后的bt:");
493         bt.preOrder();
494     }
495 }

执行结果为:

前序遍历:
HeroNode [no=1, name=宋江]
HeroNode [no=2, name=无用]
HeroNode [no=3, name=卢俊义]
HeroNode [no=5, name=关胜]
HeroNode [no=4, name=林冲]
中序遍历:
HeroNode [no=2, name=无用]
HeroNode [no=1, name=宋江]
HeroNode [no=5, name=关胜]
HeroNode [no=3, name=卢俊义]
HeroNode [no=4, name=林冲]
后序遍历:
HeroNode [no=2, name=无用]
HeroNode [no=5, name=关胜]
HeroNode [no=4, name=林冲]
HeroNode [no=3, name=卢俊义]
HeroNode [no=1, name=宋江]
前序查找:...
进入前序遍历查找......
进入前序遍历查找......
进入前序遍历查找......
进入前序遍历查找......
前序查找结果5: HeroNode [no=5, name=关胜]
进入中序遍历查找......
进入中序遍历查找......
进入中序遍历查找......
中序查找结果5: HeroNode [no=5, name=关胜]
进入后序遍历查找......
进入后序遍历查找......
中序查找结果5: HeroNode [no=5, name=关胜]
进入前序遍历查找......
进入前序遍历查找......
进入前序遍历查找......
进入前序遍历查找......
进入前序遍历查找......
前序查找结果15: null
进入中序遍历查找......
进入中序遍历查找......
进入中序遍历查找......
进入中序遍历查找......
进入中序遍历查找......
中序查找结果15: null
进入后序遍历查找......
进入后序遍历查找......
进入后序遍历查找......
进入后序遍历查找......
进入后序遍历查找......
中序查找结果15: null
测试一下delNode的方法......
删除前的bt:
HeroNode [no=1, name=宋江]
HeroNode [no=2, name=无用]
HeroNode [no=3, name=卢俊义]
HeroNode [no=5, name=关胜]
HeroNode [no=4, name=林冲]
删除后的bt:
HeroNode [no=1, name=宋江]
HeroNode [no=2, name=无用]
HeroNode [no=3, name=卢俊义]
HeroNode [no=4, name=林冲]
删除前的bt:
HeroNode [no=1, name=宋江]
HeroNode [no=2, name=无用]
HeroNode [no=3, name=卢俊义]
HeroNode [no=4, name=林冲]
删除后的bt:
HeroNode [no=1, name=宋江]
HeroNode [no=2, name=无用]

  

猜你喜欢

转载自www.cnblogs.com/redrose2100/p/12439366.html