• 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 }

      

  • 相关阅读:
    GDI绘制时钟效果,与系统时间保持同步,基于Winform
    Asp.Net Core API网关Ocelot
    Docker打包 Asp.Net Core应用,在CentOS上运行
    【C#】数据库脚本生成工具(二)
    【C#附源码】数据库文档生成工具支持(Excel+Htm)
    微信小程序初使心得【微信小程序快速入门】
    论:开发者信仰之“天下IT是一家“(Java .NET篇)
    线程池,千万注意,原来很多人都在错用
    .NET跨平台之运行与Linux上的Jexus服务器
    StackExchange.Redis 之 SortedSet 类型示例
  • 原文地址:https://www.cnblogs.com/lovesqcc/p/4038342.html
Copyright © 2020-2023  润新知