zoukankan      html  css  js  c++  java
  • java实现树的一般操作

    树是数据结构中最基本的结构,今天的博客更新一下树的基本操作:

          树的节点结构:

    package tree;  
      
      
    /**   
    * TreeNode: 普通的树节点 
    * @author xuejupo  jpxue@travelsky.com  
    * create in 2015-11-19 下午5:30:31   
    *     
    */  
    public class TreeNode<T> {  
        T value;  
              
        TreeNode<T> leftChild;  
        TreeNode<T> rightChild;  
      
        TreeNode(T value) {  
            this.value = value;  
        }  
        TreeNode() {  
        }  
          
        /**   增加左子节点 
        * addLeft:  
        * @param value  
        * void  返回类型    
        */  
        public void addLeft(T value){  
            TreeNode<T> leftChild = new TreeNode<T>(value);  
            this.leftChild = leftChild;  
        }  
        /**   
        * addRight: 增加右子节点 
        * @param value  
        * void  返回类型    
        */  
        public void addRight(T value){  
            TreeNode<T> rightChild = new TreeNode<T>(value);  
            this.rightChild = rightChild;  
        }  
        /* (non-Javadoc) 
         * @see java.lang.Object#equals(java.lang.Object) 
         * 重载equal方法 
         */  
        @Override  
        public boolean equals(Object obj) {  
            // TODO Auto-generated method stub  
            if(!(obj instanceof TreeNode)){  
                return false;  
            }  
            return this.value.equals(((TreeNode<?>)obj).value);  
        }  
        /* (non-Javadoc) 
         * @see java.lang.Object#hashCode() 
         * 重载hashCode方法 
         */  
        @Override  
        public int hashCode() {  
            // TODO Auto-generated method stub  
            return this.value.hashCode();  
        }  
        @Override  
        public String toString(){  
            return this.value==null?"":this.value.toString();  
        }  
          
          
    }  

    树的基本操作类:

    package tree;  
      
    import java.util.ArrayList;  
    import java.util.LinkedList;  
    import java.util.List;  
    import java.util.Queue;  
      
    /** 
     * TreeTools:树的操作类 
     *  
     * @author xuejupo jpxue@travelsky.com 
     *  
     *         create in 2015-11-19 下午5:31:05 
     *  
     */  
    public class TreeTools {  
      
        /** 
         * getTreeNum: 判断树中节点个数 
         *  
         * @param root 
         *            根节点 
         * @return int 返回类型 
         */  
        public static <T> int getTreeNum(TreeNode<T> root) {  
            if (root == null) {  
                return 0;  
            }  
            return getTreeNum(root.leftChild) + getTreeNum(root.rightChild) + 1;  
        }  
      
        /** 
         * getTreeDepth: 判断树的深度 
         *  
         * @param root 
         *            根节点 
         * @return int 返回类型 
         */  
        public static <T> int getTreeDepth(TreeNode<T> root) {  
            if (root == null) {  
                return 0;  
            }  
            int leftDepth = getTreeDepth(root.leftChild) + 1;  
            int rightDepth = getTreeDepth(root.rightChild) + 1;  
            return Math.max(leftDepth, rightDepth);  
        }  
      
        /** 
         * preOrderTravel: 前序遍历 
         *  
         * @param root 
         *            void 返回类型 
         */  
        public static <T> void preOrderTravel(TreeNode<T> root) {  
            if (root == null) {  
                return;  
            }  
            visitNode(root);  
            preOrderTravel(root.leftChild);  
            preOrderTravel(root.rightChild);  
        }  
      
        /** 
         * midOrderTravel: 中序遍历 
         *  
         * @param root 
         *            void 返回类型 
         */  
        public static <T> void midOrderTravel(TreeNode<T> root) {  
            if (root == null) {  
                return;  
            }  
            midOrderTravel(root.leftChild);  
            visitNode(root);  
            midOrderTravel(root.rightChild);  
        }  
      
        /** 
         * backOrderTravel: 后序遍历 
         *  
         * @param root 
         *            void 返回类型 
         */  
        public static <T> void backOrderTravel(TreeNode<T> root) {  
            if (root == null) {  
                return;  
            }  
            backOrderTravel(root.leftChild);  
            backOrderTravel(root.rightChild);  
            visitNode(root);  
        }  
      
        /** 
         * visitNode: 访问node节点 
         *  
         * @param node 
         *            void 返回类型 
         */  
        private static <T> void visitNode(TreeNode<T> node) {  
            System.out.print(node.value + "\t");  
        }  
      
        /** 
         * levelTravel: 分层遍历 
         *  
         * @param root 
         *            void 返回类型 
         */  
        public static <T> void levelTravel(TreeNode<T> root) {  
            Queue<TreeNode<T>> q = new LinkedList<TreeNode<T>>();  
            q.offer(root);  
            while (!q.isEmpty()) {  
                TreeNode<T> temp = q.poll();  
                visitNode(temp);  
                if (temp.leftChild != null) {  
                    q.offer(temp.leftChild);  
                }  
                if (temp.rightChild != null) {  
                    q.offer(temp.rightChild);  
                }  
            }  
        }  
      
        /** 
         * getNumForKlevel: 求第K层节点个数 
         *  
         * @param root 
         * @param k 
         * @return int 返回类型 
         */  
        public static <T> int getNumForKlevel(TreeNode<T> root, int k) {  
            if (root == null || k < 1) {  
                return 0;  
            }  
            if (k == 1) {  
                return 1;  
            }  
            int leftNum = getNumForKlevel(root.leftChild, k - 1);  
            int rightNum = getNumForKlevel(root.rightChild, k - 1);  
            return leftNum + rightNum;  
        }  
      
        /** 
         * getLeafNum: 求二叉树中叶子节点的个数 
         *  
         * @param root 
         * @return int 返回类型 
         */  
        public static <T> int getLeafNum(TreeNode<T> root) {  
            if (root == null) {  
                return 0;  
            }  
            if (root.leftChild == null && root.rightChild == null) {  
                return 1;  
            }  
            int leftNum = getLeafNum(root.leftChild);  
            int rightNum = getLeafNum(root.rightChild);  
            return leftNum + rightNum;  
        }  
      
        /** 
         * exchange: 交换根节点的左右子树 
         *  
         * @param root 
         * @return TreeNode 返回类型 
         */  
        public static <T> TreeNode<T> exchange(TreeNode<T> root) {  
            if (root == null) {  
                return null;  
            }  
            TreeNode<T> left = exchange(root.leftChild);  
            TreeNode<T> right = exchange(root.rightChild);  
            root.leftChild = right;  
            root.rightChild = left;  
            return root;  
        }  
      
        /** 
         * nodeIsChild: 查看node是否是root的子节点 
         *  
         * @param root 
         * @param node 
         * @return boolean 返回类型 
         */  
        public static <T> boolean nodeIsChild(TreeNode<T> root, TreeNode<T> node) {  
            if (root == null || node == null) {  
                return false;  
            }  
            if (root == node) {  
                return true;  
            }  
            boolean isFind = nodeIsChild(root.leftChild, node);  
            if (!isFind) {  
                isFind = nodeIsChild(root.rightChild, node);  
            }  
            return isFind;  
        }  
      
        /** 
         * findAllFatherNode: 返回两个节点lnode和rnode的以root为根节点的公共父节点 
         *  
         * @param root 
         *            根节点 
         * @param lNode 
         * @param rNode 
         * @return TreeNode 返回类型 
         */  
        public static <T> TreeNode<T> findAllFatherNode(TreeNode<T> root,  
                TreeNode<T> lNode, TreeNode<T> rNode) {  
            if (lNode == root || rNode == root) {  
                return root;  
            }  
            if (root == null || lNode == null || rNode == null) {  
                return null;  
            }  
            // 如果lNode是左子树的节点  
            if (nodeIsChild(root.leftChild, lNode)) {  
                if (nodeIsChild(root.rightChild, rNode)) {  
                    return root;  
                } else {  
                    return findAllFatherNode(root.leftChild, lNode, rNode);  
                }  
            } else {  
                if (nodeIsChild(root.leftChild, rNode)) {  
                    return root;  
                } else {  
                    return findAllFatherNode(root.rightChild, lNode, rNode);  
                }  
            }  
        }  
      
        /** 
         * getTreeFromPreAndMid: 根据前序和中序构建二叉树 
         *  
         * @param pre 
         *            前序序列 
         * @param mid 
         *            中序序列 
         * @return TreeNode 返回类型 
         */  
        public static <T> TreeNode<T> getTreeFromPreAndMid(List<T> pre, List<T> mid) {  
            if (pre == null || mid == null || pre.size() == 0 || mid.size() == 0) {  
                return null;  
            }  
            if (pre.size() == 1) {  
                return new TreeNode<T>(pre.get(0));  
            }  
            TreeNode<T> root = new TreeNode<T>(pre.get(0));  
            // 找出根节点在中序中的位置  
            int index = 0;  
            while (!mid.get(index++).equals(pre.get(0))) {  
            }  
            // 构建左子树的前序  
            List<T> preLeft = new ArrayList<T>(index);  
            // 左子树的中序  
            List<T> midLeft = new ArrayList<T>(index);  
            for (int i = 1; i < index; i++) {  
                preLeft.add(pre.get(i));  
            }  
            for (int i = 0; i < index - 1; i++) {  
                midLeft.add(mid.get(i));  
            }  
      
            // 重建左子树  
            root.leftChild = getTreeFromPreAndMid(preLeft, midLeft);  
            // 右子树的前序  
            List<T> preRight = new ArrayList<T>(pre.size() - index - 1);  
            // 右子树的中序  
            List<T> midRight = new ArrayList<T>(pre.size() - index - 1);  
            for (int i = 0; i <= pre.size() - index - 1; i++) {  
                preRight.add(pre.get(index + i));  
            }  
            for (int i = 0; i <= pre.size() - index - 1; i++) {  
                midRight.add(mid.get(index + i));  
            }  
            // 重建→子树  
            root.rightChild = getTreeFromPreAndMid(preRight, midRight);  
            return root;  
        }  
      
        /** 
         * equals: 查看node1和node2两棵树是否相等(两棵树所有节点都相等) 
         *  
         * @param node1 
         *            node2 两个节点 
         * @return boolean 返回类型 
         */  
        public static <T> boolean equals(TreeNode<T> node1, TreeNode<T> node2) {  
            // TODO Auto-generated method stub  
            if (node1 == null && node2 == null) {  
                return true;  
            } else if (node1 == null || node2 == null) {  
                return false;  
            }  
            boolean isEqual = node1.value.equals(node2.value);  
            boolean isLeftEqual = equals(node1.leftChild, node2.leftChild);  
            boolean isRightEqual = equals(node1.rightChild, node2.rightChild);  
            return isEqual && isLeftEqual && isRightEqual;  
        }  
    }  

    测试类:

         测试类中,先利用节点中的基本操作构建一棵树:

    public static void main(String[] args) {
            // TODO Auto-generated method stub
            TreeNode<Integer> t = new TreeNode<Integer>(1);
            t.addLeft(2);
            t.addRight(3);
            t.leftChild.addLeft(4);
            t.leftChild.addRight(5);
            System.out.println("中序遍历测试:");
            TreeTools.midOrderTravel(t);
            System.out.println("\n前序遍历测试:");
            TreeTools.preOrderTravel(t);
            System.out.println("\n后序遍历测试:");
            TreeTools.backOrderTravel(t);
            System.out.println("\n层次遍历测试:");
            TreeTools.levelTravel(t);
            System.out.println("\n树的深度:"+TreeTools.getTreeDepth(t));
            System.out.println("树的叶子个数:"+TreeTools.getLeafNum(t));
            System.out.println("树的节点个数:"+TreeTools.getTreeNum(t));
            System.out.println("第2层节点个数为:"+TreeTools.getNumForKlevel(t,2));
            List<Integer> pre = new ArrayList<Integer>();
            pre.add(1);
            pre.add(2);
            pre.add(4);
            pre.add(5);
            pre.add(3);
            List<Integer> mid = new ArrayList<Integer>();
            mid.add(4);
            mid.add(2);
            mid.add(5);
            mid.add(1);
            mid.add(3);
            TreeNode<Integer> root = TreeTools.getTreeFromPreAndMid(pre, mid);
            System.out.println("\n通过前序和中序构建树测试:");
            TreeTools.levelTravel(root);
            System.out.println("\n构建的树比较测试:");
            System.out.println(TreeTools.equals(t,root));
        }

     结果为:

    中序遍历测试:
    4    2    5    1    3    
    前序遍历测试:
    1    2    4    5    3    
    后序遍历测试:
    4    5    2    3    1    
    层次遍历测试:
    1    2    3    4    5    
    树的深度:3
    树的叶子个数:3
    树的节点个数:5
    第2层节点个数为:2
    
    通过前序和中序构建树测试:
    1    2    3    4    5    
    构建的树比较测试:
    true

    最后的话:  树的基本操作都很简单,树是我见过的最适合用递归来操作的数据结构了。因为子节点和父节点是一样的类型,而且基本具有同样的属性。

            以上的方法里面,可能只有利用前序和中序构建一棵树不容易理解。   比如图1里面那棵树,前序是1 2 4 5 3   中序是4 2 5 1 3   前序的1表示根是1,然后在中序序列里,1左边的是根节点的左子树,1后边的是整棵树的右子树,中序1前边有3个数字,右边有1个数字,表示根节点的左子树有3个节点,右子树有1个节点,所以构建根节点左子树的前序和中序时,取根节点前序的2,4,5和根节点中序的425,构建根节点右子树的前序和中序时取根节点的3,然后递归构建即可。

  • 相关阅读:
    利用 Makefile 写的小程序
    linux内核学习之进程管理------task_struct结构体
    智能指针
    explicit 关键字
    ant脚本编写
    FROM_UNIXTIME 格式化MYSQL时间戳函数
    Dubbo架构设计详解-转
    Dubbo与Zookeeper、SpringMVC整合和使用(负载均衡、容错)转
    SiteMesh详解
    sitemesh使用步骤
  • 原文地址:https://www.cnblogs.com/dawnyxl/p/9047437.html
Copyright © 2011-2022 走看看