JAVA實現二叉樹


      摘要: 一個二叉樹的Java實現。可以學習廣義表達式及二叉樹的遞歸及非遞歸處理技巧。

      難度:初級。

 

       為了克服對樹結構編程的畏懼感和神秘感,下定決心將二叉樹的大部分操作實現一遍,並希望能夠掌握二叉樹編程的一些常用技術和技巧。

      [1]  數據結構和表示: 二叉樹的輸入輸出格式采用廣義表表達式形式,內部表示采用左孩子右孩子的鏈式存儲。

      [2]  已經實現的操作有:

             A. 根據二叉樹的廣義表表達式來創建二叉樹(含表達式合法性檢測);

             B. 根據二叉樹的前序和中序遍歷列表來創建二叉樹;

             C. 根據二叉樹的中序和后序遍歷列表來創建二叉樹;

             D. 二叉樹的“左孩子右孩子”鏈式存儲轉化為廣義表表達式;

             E. 二叉樹的前序、中序、后序的遞歸和非遞歸遍歷;層序遍歷;結點關聯列表;

             F. 求解二叉樹的高度、結點總數、葉子結點總數、所有的葉子結點列表;根結點到所有葉子結點的路徑;最長路徑;

             G. 二叉樹復制,二叉樹全等性比較,二叉樹交換(將二叉樹的所有結點的左右子樹互換)

       [3]  尚待實現的操作:

             A. 求解二叉樹中所有最長(短)路徑

             E. 其它

 

       [4]  二叉樹 Java 實現代碼:

      

  1 /**
  2  * BinaryTree: 實現二叉樹,可以根據給定的廣義表表達式、前序及中序遍歷列表、中序及后序遍歷列表創建二叉樹;
  3  *             二叉樹的前序、中序、后序的遞歸和非遞歸遍歷,層序遍歷;求解二叉樹的一些特性
  4  *             
  5  * @author shuqin1984 2011-3-19
  6  * 
  7  */
  8 package datastructure.tree;
  9 import java.util.ArrayList;
 10 import java.util.Iterator;
 11 import java.util.LinkedList;
 12 import java.util.List;
 13 import java.util.regex.Matcher;
 14 import java.util.regex.Pattern;
 15 
 16 public class BinaryTree {
 17     
 18     /**    二叉樹的廣義表表示  */
 19     private String expression;
 20     /**      樹的根結點   */    
 21     private TreeNode  root;
 22     
 23     /** 
 24      * 用於檢測二叉樹廣義表表達式合法性的編譯了的正則表達式:
 25      * 合法的廣義表表達式可以是:
 26      * [1] 基本表達式: A,A(,), A(B,), A(,B), A(B,C)
 27      * [2] 上述的 A,B,C 可以是 [1] 中的基本表達式
 28      * [3] A,B,C 可允許的取值范圍由應用決定,這里僅允許是 大小寫字母,數字,+-/*%
 29      * [4] 表達式中不含任何空格符,因此,在檢查表達式之前,必須確保表達式中不含空格符
 30      * 
 31      */
 32     private static String permittedChars = "[a-zA-Z0-9//+//-//*/////%]";
 33     private static String basicUnit = "[a-zA-Z0-9//+//-//*/////%//(//),]";
 34     private static Pattern basicPattern = Pattern.compile("" + "|" + permittedChars + "|" + permittedChars + "//(" + permittedChars + "?," + permittedChars + "?//)?");
 35     private static Pattern extendPattern = Pattern.compile(permittedChars + "//(" + basicUnit + "*," + basicUnit + "*//)");
 36     
 37     /**
 38      * 構造器
 39      * @param root 樹的根結點
 40      */
 41     public BinaryTree(TreeNode root) {
 42         this.root = root;
 43     }
 44     
 45     /**
 46      * 構造器
 47      * @param expression 二叉樹的廣義表表達式
 48      */
 49     private BinaryTree(String expression) {
 50         this.expression = expression;
 51     }
 52     /**
 53      * 樹結點實現
 54      */
 55     private class TreeNode {
 56         
 57         private char ch;
 58         private TreeNode rchild;
 59         private TreeNode lchild;
 60         
 61         public TreeNode(char ch, TreeNode rchild, TreeNode lchild) {
 62             this.ch = ch;
 63             this.rchild = rchild;
 64             this.lchild = lchild;
 65         }
 66         public char getCh() {
 67             return ch;
 68         }
 69         public TreeNode getRchild() {
 70             return rchild;
 71         }
 72         public void setRchild(TreeNode rchild) {
 73             this.rchild = rchild;
 74         }
 75         public TreeNode getLchild() {
 76             return lchild;
 77         }
 78         public void setLchild(TreeNode lchild) {
 79             this.lchild = lchild;
 80         }    
 81         
 82         public String toString()
 83         {
 84             return "" + getCh();
 85         }
 86     }
 87     
 88     /**
 89      * 結點關聯類
 90      */
 91     private class NodeLink {
 92         
 93         private TreeNode node1;
 94         private TreeNode node2;
 95         
 96         public NodeLink(TreeNode node1, TreeNode node2) {
 97             this.node1 = node1;
 98             this.node2 = node2;
 99         }
100         
101         public String toString() {
102             
103             return "(" + node1.getCh() + "," + node2.getCh() + ")";
104         }
105             
106     }
107     
108     /**
109      *  【設置/獲取】屬性
110      */
111     public TreeNode getRoot() {
112         return root;
113     }
114     public void setRoot(TreeNode root) {
115         this.root = root;
116     }
117     
118     
119     /**
120      * getPreOrderList: 獲得樹的先序遍歷列表
121      * @param flag 是否采用遞歸遍歷的標記;若 flag = true, 采用遞歸遍歷;否則,采用非遞歸遍歷
122      * @return 二叉樹的先序遍歷列表
123      */
124     
125     public List<TreeNode> getPreOrderList(boolean flag) {
126         
127         List<TreeNode>    nodelist = new ArrayList<TreeNode>();
128         if (flag == true) {
129            nodelist = preOrderTraverse(getRoot(), nodelist);
130         }
131         else {
132            nodelist = preOrderTraverseIter(getRoot());
133         }
134         return nodelist;
135     }
136     
137     /**
138      * getInOrderList: 獲得樹的中序遍歷列表
139      * @param flag 是否采用遞歸遍歷的標記;若 flag = true, 采用遞歸遍歷;否則,采用非遞歸遍歷
140      * @return 獲得樹的中序遍歷列表
141      */
142     
143     public List<TreeNode> getInOrderList(boolean flag) {
144         
145         List<TreeNode>    nodelist = new ArrayList<TreeNode>();
146         if (flag == true) {
147            nodelist = inOrderTraverse(getRoot(), nodelist);
148         }
149         else {
150            nodelist = inOrderTraverseIter(getRoot());
151         }
152         return nodelist;
153     }
154     
155     /**
156      * getPostOrderList: 獲得樹的后序遍歷列表
157      * @param flag 是否采用遞歸遍歷的標記;若 flag = true, 采用遞歸遍歷;否則,采用非遞歸遍歷
158      * @return 獲得樹的后序遍歷列表
159      */
160     
161     public List<TreeNode> getPostOrderList(boolean flag) {
162         
163         List<TreeNode>    nodelist = new ArrayList<TreeNode>();
164         if (flag == true) {
165             nodelist = postOrderTraverse(getRoot(), nodelist);
166         }
167         else {
168             nodelist = postOrderTraverseIter(getRoot());
169         }
170         return nodelist;
171     }
172     
173     /**
174      * 獲得樹的層序遍歷列表
175      * 
176      * @return 獲得樹的層序遍歷列表
177      */
178     
179     public List<TreeNode> getFloorOrderList() {
180         
181         List<TreeNode>    nodelist = new ArrayList<TreeNode>();
182         nodelist = floorOrderTraverse(getRoot());
183         return nodelist;
184     }
185     
186     /**
187      * createBinaryTree: 根據樹的廣義表表示構造二叉樹
188      * @throws Exception 
189      */
190     public static BinaryTree createBinaryTree(String expression) throws Exception 
191     {
192         BinaryTree bt = new BinaryTree(trimSpace(expression));
193         bt.createBinaryTree();
194         return bt;
195     }
196     
197     /**
198      * createBinaryTree: 根據二叉樹的廣義表表達式來創建二叉樹
199      * @exception 若二叉樹的廣義表表達式不合法,則拋出異常
200      */
201     private void createBinaryTree() throws Exception {
202         
203         // 檢查傳入的二叉樹廣義表示法是否合法有效
204         if (!checkValid(expression))
205             throw new Exception("廣義表表達式不合法,無法創建二叉樹!");
206         
207         // 使用 LinkedList 來執行棧的功能
208         LinkedList<TreeNode> stack = new LinkedList<TreeNode>();
209         TreeNode newnode = null;
210         int flag = 0;  //  flag = 0: 創建左子樹 | flag = 1: 創建右子樹
211         
212         for (char ch: expression.toCharArray()) {
213             switch (ch) {
214                
215                // 遇到  "(" 時,表示該結點可能有孩子結點,將該父結點壓入棧中
216                case '(': 
217                    stack.push(newnode);
218                    flag = 0;
219                    break;
220                    
221                // 遇到  ")" 時,表示已經掃描完父結點的右孩子結點的值,彈出該父結點       
222                case ')':
223                    stack.pop();
224                    break;
225                    
226               // 遇到 "," 時, 表示將要掃描父結點的右孩子結點的值。       
227                case ',':
228                    flag = 1;
229                    break;       
230               
231               // 遇到結點的值,將其加入二叉樹中       
232                default:
233                    
234                     newnode = new TreeNode(ch, null, null);
235                     if (root == null) {
236                            root = newnode;
237                     }
238                     else {
239                            if (flag == 0) {
240                               TreeNode topnode = stack.peek();
241                               topnode.setLchild(newnode);
242                            }
243                            else 
244                            {
245                                TreeNode topnode = stack.peek();
246                                topnode.setRchild(newnode); 
247                            }
248                     }
249                     break;           
250             }
251         }        
252     }
253     
254     /**
255      * checkValid: 判斷給定二叉樹的廣義表表示是否合法有效
256      *             
257      * @param expression 給定二叉樹的廣義表表示【字符串形式】
258      * @return 如果給定的二叉樹廣義表表示合法有效,返回true; 否則,返回 false
259      * 
260      */
261     private static boolean checkValid(String expression)
262     {
263         Matcher m = null;
264         if (basicPattern.matcher(expression).matches())
265             return true;
266         else if ((m = extendPattern.matcher(expression)).matches()) {
267             int index = separatorIndex(expression);
268             if (index == -1) {  // 不存在能夠分割二叉樹廣義表達式的左右子樹表達式的逗號
269                 return false;
270             }
271             String rightEx = "";
272             String leftEx = ""; 
273             if (index > 2) {
274                 leftEx = expression.substring(2, index);  // 左子樹的廣義表達式
275             }
276             if (index < expression.length()-2) { 
277                   rightEx = expression.substring(index+1, expression.length()-1);  // 右子樹的廣義表達式
278             }
279             return checkValid(leftEx) && checkValid(rightEx);        
280         }
281         else {
282             return false;
283         }
284     }
285     
286     
287     /**
288      * getGeneralList: 獲取該二叉樹的廣義表表示(字符串表示)
289      */
290     public String getGeneralListString()
291     {
292         StringBuilder sb = new StringBuilder("");
293         if (expression == null) {
294             createGeneralList(root, sb);
295             return sb.toString();
296         }
297         return  expression;        
298     }
299     
300     /**
301      * getGeneralList: 根據給定二叉樹生成其廣義表表示(字符串形式)
302      * @param root 樹的根結點
303      * @return 樹的廣義表表示【字符串形式】
304      */    
305     private void createGeneralList(TreeNode root, StringBuilder sb) {
306         
307         if (root != null) {
308             
309             sb.append(root.getCh());
310             if (root.getLchild() != null || root.getRchild() != null) {
311                 sb.append('(');
312                 if (root.getLchild() != null) {
313                     createGeneralList(root.getLchild(), sb);
314                 }
315                 sb.append(',');
316                 if (root.getRchild() != null) {                
317                     createGeneralList(root.getRchild(), sb);        
318                 }
319                 sb.append(')');
320             }    
321         }            
322     }
323     
324     /**
325      * size: 獲取二叉樹的結點總數
326      *  
327      * @param root 樹的根結點
328      * @return  樹的結點總數
329      * 
330      */
331     public int size(TreeNode root) {
332         
333         if (root == null)
334             return 0;
335         else {
336             return size(root.getLchild()) + size(root.getRchild()) + 1;
337         }
338     }
339     
340     /**
341      * leafCounter: 獲取二叉樹的葉子結點數目
342      * 
343      * @param root 樹的根結點
344      * @return  樹的葉子結點數目
345      * 
346      */
347     public int leafCounter(TreeNode root) {
348         if (root == null)
349             return 0;
350         else {
351             if (root.getLchild() == null && root.getRchild() == null)
352                 return 1;
353             else
354                 return leafCounter(root.getLchild()) + leafCounter(root.getRchild());
355         }
356     }
357     
358     /**
359      * getLeafNodes : 獲取該二叉樹的所有葉子結點
360      */
361     public List<TreeNode> getLeafNodes()
362     {
363         List<TreeNode> leaflist = new ArrayList<TreeNode>();
364         getLeafNodes(getRoot(), leaflist);
365         return leaflist;
366     }
367     
368     /**
369      * printLeafPaths : 打印該二叉樹的所有葉子結點到根的路徑
370      */
371     public void printLeafPaths()
372     {
373         List<TreeNode> leafPath = new ArrayList<TreeNode>();
374         buildLeafPaths(root, leafPath);
375     }
376     
377     /**
378      * buildLeafPaths : 遞歸求解給定二叉樹的所有葉子結點到根的路徑
379      * @param root 給定二叉樹的根結點
380      * @param path 存放某個葉子結點到根的路徑
381      */
382     public void buildLeafPaths(TreeNode root, List<TreeNode> path)
383     {
384         if (root != null) {    
385             path.add(root);  // 將從根結點到葉子結點的路徑上的結點保存起來
386             if (root.getLchild() == null && root.getRchild() == null) { // 到達葉子結點,完成一條路徑,並可對其處理
387                 processPath(path);
388             }
389             else {
390                 buildLeafPaths(root.getLchild(), path);
391                 if (root.getLchild() != null) {      
392                    path.remove(path.size()-1);  // 回溯,從左子樹到右子樹,刪除前一條路徑上的葉子結點
393                 }
394                 buildLeafPaths(root.getRchild(), path);
395                 if (root.getRchild() != null) {
396                    path.remove(path.size()-1);
397                 }
398             }
399         }
400     }
401     
402     /**
403      * processPath : 處理從某葉子結點到根結點的路徑的操作
404      */
405     private void processPath(List<TreeNode> path)
406     {
407         System.out.println(listToString(path));
408     }
409     
410     /**
411      * getLeafNodes: 遞歸求解給定二叉樹的所有葉子結點
412      * @param root   給定二叉樹的根結點
413      * @param leaflist 給定二叉樹的所有葉子結點
414      */
415     private void getLeafNodes(TreeNode root, List<TreeNode> leaflist)
416     {
417         if (root != null) {
418             if (root.getLchild() == null && root.getRchild() == null) {
419                 leaflist.add(root);
420                 return ;
421             }
422             getLeafNodes(root.getLchild(), leaflist);
423             getLeafNodes(root.getRchild(), leaflist);
424         }
425     }
426     
427     
428     /**
429      * height: 獲取二叉樹的高度 
430      * 
431      * @param root   樹的根結點
432      * @return       樹的高度
433      *  
434      */
435     
436     public int height(TreeNode root)
437     {
438         if (root == null)
439             return 0;
440         else
441             return 1 + Math.max(height(root.getLchild()), height(root.getRchild()));
442     }
443     
444     /**
445      * getNodelinkList: 獲取該二叉樹的結點關聯列表
446      * @return 樹的結點關聯列表
447      */
448     public List<NodeLink> getNodelinkList() {
449         
450         List<NodeLink> linklist = new ArrayList<NodeLink>();
451         createNodelinkList(getRoot(), linklist);
452         return linklist;
453         
454     }
455         
456     /**
457      * createNodelinkList: 遞歸求解給定二叉樹的結點關聯列表表示
458      * @param root 給定二叉樹的根結點
459      * @param linklist 存放給定二叉樹的結點關聯對象
460      */
461     private void createNodelinkList(TreeNode root, List<NodeLink> linklist) {
462         
463         if (root != null) {
464             if (root.getLchild() != null) {
465                 NodeLink nodelink = new NodeLink(root, root.getLchild());
466                 linklist.add(nodelink);
467                 createNodelinkList(root.getLchild(), linklist);
468             }
469             if (root.getRchild() != null) {
470                 NodeLink nodelink = new NodeLink(root, root.getRchild());
471                 linklist.add(nodelink);
472                 createNodelinkList(root.getRchild(), linklist);
473             }
474         }
475     }
476     
477     /**
478      * preOrderTraverse: 二叉樹的遞歸先序遍歷
479      * 
480      */
481     private List<TreeNode> preOrderTraverse(TreeNode root, List<TreeNode> nodelist) {
482         
483         if (root != null) {
484             nodelist.add(root);
485             preOrderTraverse(root.getLchild(), nodelist);    
486             preOrderTraverse(root.getRchild(), nodelist);
487         }
488         
489         return nodelist;
490     }
491     
492     /**
493      * preOrderTraverseIter: 二叉樹的非遞歸先序遍歷
494      */
495     private List<TreeNode> preOrderTraverseIter(TreeNode root) {
496         LinkedList<TreeNode> stack = new LinkedList<TreeNode>();
497         List<TreeNode> nodelist = new ArrayList<TreeNode>();
498         TreeNode pNode = root;
499         for (;;) {
500             while (pNode != null) {
501                 nodelist.add(pNode);        // 訪問根結點
502                 stack.push(pNode);          // 根結點入棧    
503                 pNode = pNode.getLchild();  // 訪問左子樹
504             }    
505             pNode = stack.pop();
506             pNode = pNode.getRchild();      // 訪問右子樹
507             if (pNode == null && stack.isEmpty()) { break; }
508         }           
509         return nodelist;
510     }
511     
512     /**
513      * inOrderTraverse: 二叉樹的遞歸中序遍歷
514      * 
515      */
516     private List<TreeNode> inOrderTraverse(TreeNode root, List<TreeNode> nodelist) {
517         
518         if (root != null) {
519             inOrderTraverse(root.getLchild(), nodelist);
520             nodelist.add(root);
521             inOrderTraverse(root.getRchild(), nodelist);
522         }
523         
524         return nodelist;
525     }
526     
527     /**
528      * inOrderTraverseIter: 二叉樹的非遞歸中序遍歷
529      */
530     
531     private List<TreeNode> inOrderTraverseIter(TreeNode root) {
532         
533         LinkedList<TreeNode> stack = new LinkedList<TreeNode>();
534         List<TreeNode> nodelist = new ArrayList<TreeNode>();
535         
536         TreeNode pNode = root;
537         for (;;) {
538             while (pNode != null) {            // 訪問左子樹
539                 stack.push(pNode);      
540                 pNode = pNode.getLchild();
541             }
542             pNode = stack.pop();   
543             nodelist.add(pNode);               // 訪問根結點
544             pNode = pNode.getRchild();           // 訪問右子樹
545             if (pNode == null && stack.isEmpty()) { break; }
546         }
547         
548         return nodelist;
549     }
550     
551     /**
552      * postOrderTraverse: 二叉樹的遞歸后序遍歷
553      */
554     private List<TreeNode> postOrderTraverse(TreeNode root, List<TreeNode> nodelist) {
555         
556         if (root != null) {
557             postOrderTraverse(root.getLchild(), nodelist);
558             postOrderTraverse(root.getRchild(), nodelist);
559             nodelist.add(root);
560         }
561         
562         return nodelist;
563     }
564     
565     /**
566      * postOrderTraverseIter: 二叉樹的非遞歸后序遍歷
567      */
568     private List<TreeNode> postOrderTraverseIter(TreeNode root) {
569         
570         LinkedList<TreeNode> stack = new LinkedList<TreeNode>();
571         List<TreeNode> nodelist = new ArrayList<TreeNode>();
572         
573         int flag = 0;  // 標識是否訪問過右子樹; flag = 0 表示沒有訪問; flag = 1 表示已經訪問過
574         TreeNode pNode = root;
575         TreeNode tmpNode = null;
576         loop1:
577         for (;;) {
578             while (pNode != null) {        // 訪問左子樹
579                 stack.push(pNode);     
580                 pNode = pNode.getLchild();
581                 flag = 0;
582             }
583             loop2:
584             for (;;) {
585                 if (!stack.isEmpty()) {
586                     
587                     if (flag == 0)               // 尚未訪問根結點的右子樹
588                     {
589                        pNode = stack.peek();     // 取根結點的右子樹,訪問其右子樹
590                        pNode = pNode.getRchild(); 
591                        flag = 1;
592                        continue loop1;
593                     }
594                     
595                     if (flag == 1) {            // 已經訪問過右子樹
596                         pNode = stack.pop();
597                         nodelist.add(pNode);    // 訪問根結點,實際上是左右子樹均為空的葉子結點 
598                         tmpNode = pNode;        // 訪問某個結點后,立即訪問其父結點的右子樹
599                         pNode = stack.peek();   // 取該結點的父結點    
600                         if (pNode != null) {    // 父結點不為空(沒有回溯到整棵樹的根結點)
601                             if (tmpNode == pNode.getRchild()) { 
602                                 // 如果剛剛訪問的結點正是其父結點的右孩子,則直接回溯訪問其父結點; 
603                                 continue loop2; 
604                             }
605                             else {  // 否則,訪問其父結點的右子樹
606                                 pNode = pNode.getRchild();
607                                 continue loop1;
608                             }
609                         } 
610                         
611                     }
612                     
613                     
614                 }
615                 else   // 棧空,遞歸調用結束,退出
616                 {
617                     break loop1;
618                 }
619             }    
620             
621         }
622         return nodelist;
623     }
624     
625     /**
626      * floorOrderTraverse: 二叉樹的層序遍歷
627      * 
628      * @param  root 樹的根結點
629      * @return 樹的層序遍歷列表
630      * 
631      */
632     private List<TreeNode> floorOrderTraverse(TreeNode root) {
633         
634         // 使用 LinkedList 來執行隊列的功能
635         LinkedList<TreeNode> queue = new LinkedList<TreeNode>();
636         List<TreeNode> nodelist = new ArrayList<TreeNode>();
637         if (root != null) {
638             nodelist.add(root);
639             queue.addLast(root);
640             while(queue.size() > 0) {
641                 TreeNode node = queue.removeFirst();
642                 if (node.getLchild() != null) {
643                     nodelist.add(node.getLchild());
644                     queue.addLast(node.getLchild());
645                 }   
646                 if (node.getRchild() != null) {
647                     nodelist.add(node.getRchild());
648                     queue.addLast(node.getRchild());
649                 }    
650             }
651         }
652         
653         return nodelist;
654     }
655     
656     /**
657      * copyBinaryTree: 復制二叉樹
658      * @return 復制后的二叉樹
659      */
660     public BinaryTree copyBinaryTree()
661     {
662         TreeNode anotherRoot = null;
663         anotherRoot = copy(getRoot());
664         return new BinaryTree(anotherRoot);
665     }
666     
667     /**
668      * copy: 復制二叉樹
669      * @param srcRoot 要復制的二叉樹的根結點
670      * @param destRoot 目標二叉樹的根結點
671      */
672     private TreeNode copy(TreeNode srcRoot)
673     {
674         if (srcRoot != null) {
675             TreeNode newNode = new TreeNode(srcRoot.getCh(), null, null);
676             newNode.setLchild(copy(srcRoot.getLchild()));
677             newNode.setRchild(copy(srcRoot.getRchild()));
678             return newNode;
679         }
680         return null;
681     }
682     
683     /**
684      * equalsTo: 比較該二叉樹與給定二叉樹 another 是否全等;
685      *           若全等則返回 true, 否則返回 false.
686      */
687     public boolean equalsTo(BinaryTree another)
688     {
689         return compareEqual(root, another.getRoot());
690     }
691     
692     /**
693      * equalsTo : 比較給定的兩個二叉樹是否全等
694      *            兩個二叉樹全等當且僅當 
695      *            A. 兩個二叉樹均為空; 或者 
696      *            B. 兩個二叉樹均非空,且所有對應位置的結點都相同,對應結點之間的關聯也完全相同.
697      */
698     private boolean compareEqual(TreeNode root, TreeNode anotherRoot)
699     {
700         return (root == null && anotherRoot == null) || 
701                ((root != null && anotherRoot != null) &&
702                 (root.getCh() == anotherRoot.getCh()) &&
703                 (compareEqual(root.getLchild(), anotherRoot.getLchild())) && 
704                 (compareEqual(root.getRchild(), anotherRoot.getRchild())));
705     }
706     
707     /**
708      * swapTree : 將該二叉樹的所有結點的左右孩子互換
709      */
710     public void swapTree()
711     {
712         StringBuilder sb = new StringBuilder("");
713         swapTree(root);
714         createGeneralList(root, sb);
715         expression = sb.toString();
716     }
717     
718     /**
719      * swapTree : 將給定的二叉樹的所有結點的左右孩子互換
720      * @param root 給定二叉樹的根結點
721      */
722     private void swapTree(TreeNode root)
723     {
724         if (root != null) {
725             TreeNode tmp = root.getLchild();
726             root.setLchild(root.getRchild());
727             root.setRchild(tmp);
728             swapTree(root.getLchild());
729             swapTree(root.getRchild());
730         }
731     }
732      
733     /**
734      * longestPath: 獲取該二叉樹中的一條最長路徑
735      * @return 二叉樹中的一條最長路徑
736      */
737     public List<TreeNode> longestPath() 
738     {
739         List<TreeNode> longestPath = new ArrayList<TreeNode>();
740         longestPath(root, longestPath);
741         return longestPath;
742     }
743     
744     /**
745      * longestPath: 遞歸求解給定二叉樹的一條最長路徑
746      * @param root  給定二叉樹的根結點
747      * @param longestPath 存放二叉樹的最長路徑上的結點
748      */
749     private void longestPath(TreeNode root, List<TreeNode> longestPath)
750     {
751         if (root != null) {
752             longestPath.add(root);
753             if (root.getLchild() == null && root.getRchild() == null) { // 左右子樹均空
754                  return ;
755             }
756             if (root.getLchild() != null && root.getRchild() == null) { // 左子樹非空,右子樹為空,則最長路徑的結點必在左子樹路徑上
757                 longestPath(root.getLchild(), longestPath);
758             }
759             if (root.getLchild() == null && root.getRchild() != null) { // 左子樹非空,右子樹為空,則最長路徑的結點必在右子樹路徑上
760                 longestPath(root.getRchild(), longestPath);
761             }
762             if (root.getLchild() != null && root.getRchild() != null) { // 左右子樹均非空;分別求解左右子樹的最長路徑,取最大者
763                 List<TreeNode> leftLongestPath = new ArrayList<TreeNode>();
764                 List<TreeNode> rightLongestPath = new ArrayList<TreeNode>();
765                 longestPath(root.getLchild(), leftLongestPath);
766                 longestPath(root.getRchild(), rightLongestPath);
767                 if (leftLongestPath.size() >= rightLongestPath.size()) {
768                     longestPath.addAll(leftLongestPath);
769                 } else if (leftLongestPath.size() < rightLongestPath.size()) {
770                     longestPath.addAll(rightLongestPath);
771                 }
772                 
773             }
774         }
775     }
776     
777     
778     
779     /**
780      * listToString: 返回二叉樹的結點列表的字符串表示
781      * 
782      * @param nodelist  樹的結點列表
783      * @return  二叉樹的結點列表的字符串表示 
784      * 
785      */
786     public String listToString(List<TreeNode> nodelist) {
787         
788         if (nodelist == null || nodelist.size() == 0) {
789             return "[ 空樹 ]";
790         }
791         StringBuilder str = new StringBuilder("[");
792         Iterator<TreeNode> iter = nodelist.iterator();
793         while (iter.hasNext()) {
794             TreeNode node = iter.next();
795             str.append(node.getCh()+" ");
796         }
797         str.deleteCharAt(str.length()-1);
798         str.append(']');
799         return str.toString();
800     }
801     
802     
803     /**
804      * createBinaryTree: 根據前序和中序遍歷列表生成二叉樹
805      * 
806      * @param preOrderList  前序列表字符串
807      * @param inOrderList   中序列表字符串
808      * @throws Exception 
809      * 
810      */
811     public static BinaryTree createBinaryTree(String preOrderList, String inOrderList) throws Exception {
812         BinaryTree bt = new BinaryTree(getGeneralList(preOrderList, inOrderList));
813         bt.createBinaryTree();
814         return bt;
815     }
816     
817     /**
818      * getGeneralist: 根據前序和中序遍歷列表生成二叉樹的廣義表表示【字符串形式】
819      * 
820      * @param preOrderList  前序列表字符串
821      * @param inOrderList   中序列表字符串
822      * @return generalList  廣義表表示
823      * 
824      */
825     
826     private static String getGeneralList(String preOrderList, String inOrderList) {
827         
828         String s = "";
829         if (preOrderList.length() > 0 || inOrderList.length() > 0) {
830             
831             // 如果只含一個結點值,就直接返回
832             if (preOrderList.length() == 1)
833                 return preOrderList;
834             
835             // 根據前序遍歷, 第一個是根結點的值
836             char ch = preOrderList.charAt(0); 
837             
838             // 根據中序遍歷及根結點,將前序列表分為左右子樹列表。
839             int index = inOrderList.indexOf(ch);
840             String inOrderLeft = inOrderList.substring(0, index);                     // 左子樹的中序遍歷列表
841             String inOrderRight = inOrderList.substring(index+1);                     // 右子樹的中序遍歷列表
842             String preOrderLeft = preOrderList.substring(1, inOrderLeft.length()+1);  // 左子樹的前序遍歷列表
843             String preOrderRight = preOrderList.substring(inOrderLeft.length()+1);    // 右子樹的前序遍歷列表
844             s += ch;
845             s += "(" + getGeneralList(preOrderLeft,inOrderLeft) + "," + getGeneralList(preOrderRight,inOrderRight) + ")"; 
846         }
847         return s;
848     }
849     
850     /**
851      * createBinaryTree: 根據中序和后序遍歷列表生成二叉樹
852      * 
853      * @param  inOrderList   中序列表
854      * @param  postOrderList 后序列表
855      * @param  flag          標記
856      * 
857      * @throws Exception 
858      */
859     public static BinaryTree createBinaryTree(String inOrderList, String postOrderList, boolean flag) throws Exception {
860         BinaryTree bt = new BinaryTree(getGeneralList(inOrderList, postOrderList, flag));
861         bt.createBinaryTree();
862         return bt;
863     }
864     
865     
866     
867     /**
868      * getGeneralList: 根據中序和后序遍歷生成二叉樹的廣義表表示【字符串形式】
869      * 
870      * @param  inOrderList   中序列表
871      * @param  postOrderList 后序列表
872      * @param  flag          標記
873      * @return generalList   廣義表表示
874      * 
875      */
876     
877     private static String getGeneralList(String inOrderList, String postOrderList, boolean flag) {
878         
879         String s = "";
880         if (inOrderList.length() > 0 || postOrderList.length() >0) {
881             
882             // 如果只含一個結點值,就直接返回
883             if (inOrderList.length() == 1) 
884                 return inOrderList;
885             
886             // 根據后序遍歷規則,最后一個是根結點的值
887             char ch = postOrderList.charAt(postOrderList.length()-1); 
888             
889             // 根據中序遍歷及根結點,將前序列表分為左右子樹列表。
890             int index = inOrderList.indexOf(ch);
891             String inOrderLeft = inOrderList.substring(0, index);                     // 左子樹的中序遍歷列表
892             String inOrderRight = inOrderList.substring(index+1);                     // 右子樹的中序遍歷列表
893             String postOrderLeft = postOrderList.substring(0, inOrderLeft.length());  // 左子樹的前序遍歷列表
894             String postOrderRight = postOrderList.substring(inOrderLeft.length(), 
895                                     inOrderLeft.length()+inOrderRight.length());    // 右子樹的前序遍歷列表
896             s += ch;
897             s += "(" + getGeneralList(inOrderLeft,postOrderLeft,true) + "," + getGeneralList(inOrderRight,postOrderRight,true) + ")"; 
898         }
899         return s;
900     }
901     
902     /**
903      * trimSpace: 將廣義表表達式字符串中的空格符去掉
904      */
905     private static String trimSpace(String s)
906     {
907         StringBuilder sb = new StringBuilder("");
908         for (int i=0; i < s.length(); i++) {
909             char ch = s.charAt(i);
910             if (!(new Character(ch).toString().matches("//s"))) {   
911                 sb.append(ch);
912             }
913         }
914         return sb.toString();
915     }
916     
917     /**
918      * separatorIndex : 求解廣義表表達式中分割左右子樹的分隔符的位置
919      *                  由於這里使用逗號分割左右子樹,則當且僅當其位置應當滿足:
920      *                  在該分割符之前,左括號的數目恰好比右括號的數目多1. 
921      * @return  若存在滿足條件的分隔符,則返回其位置;否則返回 -1
922      */
923     private static int separatorIndex(String expression)
924     {
925         int leftBracketCounter=0, rightBacketCounter=0;
926         int index = 0;
927         for (; index < expression.length(); index++) {
928             char ch = expression.charAt(index);
929             if (ch == '(') {
930                 leftBracketCounter++;
931             }
932             else if (ch == ')') {
933                 rightBacketCounter++;
934             }
935             else if (ch == ',') {
936                 if (leftBracketCounter == rightBacketCounter+1) break;
937             }
938         }
939         if (index < expression.length()) {
940             return index;
941         }
942         return -1;
943     }
944     
945 }

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM