树递归算法要点精析

Posted zqiguoshang

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树递归算法要点精析相关的知识,希望对你有一定的参考价值。

树的递归脱不了三种递归遍历的范畴。所以看到树的递归算法,先想清楚是哪种遍历,需要哪种遍历,这可大大降低复杂度。

虽然遍历过程,每个节点会走3遍,但实际访问就一遍。所以在递归结束判断中,最好每层只判断当前节点。

在整层递归中,每一层要把一层的事情做完,然后将结果返回上一层。这样也便于判断正误。

由于递归是深度优先执行,我们无法保证广度方向的同层性。所以如果需要广度方向的同层性保证,要引入辅助数组。

最后,适当的添加辅助参数,如层次等信息,可极大简化算法。

 

下面给出几个递归算法:

   /**
     * count the number of leaves in a tree.
     * @param root Node root of tree
     * @return int  leaves number
     */
    public static int numOfLeaves(Node root){
        if (root == null) return 0;
        if (root.left == null && root.right == null) return 1;
        return numOfLeaves(root.left) + numOfLeaves(root.right);
    }

    /**
     * change all the left sub-tree and right sub-tree position in the tree.
     * @param root
     */
    public static void changeLeftAndRight(Node root){
        if (root != null){
            changeLeftAndRight(root.left);
            changeLeftAndRight(root.right);
            Node tmp = root.left;
            root.left = root.right;
            root.right = tmp;
        }
    }

    /**
     * count the number of node whose degree is 1
     * @param root number
     */
    public static int numOf1degree(Node root){
        if (root == null) return 0;
        int sum = numOf1degree(root.left) + numOf1degree(root.right);
        if (root.right == null && root.left != null || root.left == null && root.right != null) return sum + 1;
        return sum;
    }

    /**
     * count the number of nodes whose degree are 2.
     * @param root
     * @return number
     */
    public static int numOf2degree(Node root){
        if (root == null) return 0;
        int sum = numOf2degree(root.left) + numOf2degree(root.right);
        if (root.right != null && root.left != null) return sum + 1;
        return sum;
    }

    public static int numOf0degree(Node root){
        if (root == null) return 0;
        if (root.right == null && root.left == null) return 1;
        return numOf0degree(root.left) + numOf0degree(root.right);
    }

    /**
     * return the deep of the tree.
     * @param root
     * @return  deep of tree
     */
    public static int deepOfTree(Node root){
        if (root == null) return 0;
        int left = deepOfTree(root.left);
        int right = deepOfTree(root.right);
        return left > right ? left + 1 : right + 1;
    }

    /**
     * return width of the tree. we have a wideArray which stores every level width of the tree.
     * what we need to do is find the max width.
     * @param root root of the tree
     * @return width of tree
     */
    public static int wideOfTree(Node root){
        int[] wideArray = new int[20];
        wideOfTree(root, wideArray,0);
        int max = 0;
        for (int i: wideArray) {
            if (i > max){
                max = i;
            }
        }
        return max;
    }

    /**
     * private width of tree
     * Recursion is deep first traversal. But calculate the width of tree is hierarchical operation.
     * Without extra help, we cannot guarantee the recursion nodes are in the same level.
     * @param root root of tree
     * @param wideArray we need to store the width of every level. so we need a wideArray to help.
     * @param level level of root
     */
    public static void wideOfTree(Node root, int[] wideArray, int level){
        if (root != null){
            wideArray[level] += 1;
            wideOfTree(root.left, wideArray, level+1);
            wideOfTree(root.right, wideArray, level+1);
        }
    }


    /**
     * return the level of the specified node.
     * @param root root of the tree.
     * @param p the specified node
     * @param level the level of root
     * @return the level of the specified node
     */
    public static int levelOfP(Node root, Node p, int level){
        if (root == null) return 0;
        if (root == p) return level + 1;
        int left = levelOfP(root.left, p, level+1);
        int right = levelOfP(root.right, p, level+1);
        return left > right ? left : right;
    }

    /**
     * delete all leaf nodes of the tree
     * @param root the root of the tree
     */
    public static void deleteAllLeaves(Node root){
        if (root == null) return;
        if (root.left == null && root.right == null) {
            root = null;
            return;
        }
        deepOfTree(root.left);
        deepOfTree(root.right);
    }

    /**
     * use suffix traversal to realize the function.
     * In every recursion level , return the max of the parent value and the sub-tree value.
     * return the value of the node which has the max value
     * @param root root of the tree
     * @param lastMax the max value of parent node. should be initialized by Integer.MIN_VALUE
     * @return the max node value of the tree
     */
    public static int valueOfMaxNode(Node root, int lastMax){
        if (root == null) return lastMax;
        if (root.value > lastMax) lastMax = root.value;
        int maxLeft = valueOfMaxNode(root.left, lastMax);
        int maxRight = valueOfMaxNode(root.right, lastMax);
        return maxLeft > maxRight ? maxLeft : maxRight;
    }

    public static void printNodeInfoByInfixTraversal(Node root, int level) {
        if (root != null){
            System.out.print("( "+ root.value + " " + level + ") ");
            printNodeInfoByInfixTraversal(root.left, level+1);
            printNodeInfoByInfixTraversal(root.right, level+1);
        }
    }

  

 

以上是关于树递归算法要点精析的主要内容,如果未能解决你的问题,请参考以下文章

决策树一

[XJTUSE 算法设计与分析] 第五章 回溯法

二叉树遍历算法

美赛常用算法与获奖论文精析,助力美赛备战!

每天刷个算法题20160521:二叉树高度(递归与非递归)

二叉树遍历的递归算法