树递归算法要点精析

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

虽然遍历过程,每个节点会走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);
        }
    }

  

时间: 2024-12-13 02:49:22

树递归算法要点精析的相关文章

MVVM大比拼之vue.js源码精析

VUE 源码分析 简介 Vue 是 MVVM 框架中的新贵,如果我没记错的话作者应该毕业不久,现在在google.vue 如作者自己所说,在api设计上受到了很多来自knockout.angularjs等大牌框架影响,但作者相信 vue 在性能.易用性方面是有优势.同时也自己做了和其它框架的性能对比,在这里.今天以版本 0.10.4 为准 入口 Vue 的入口也很直白: ? 1 var demo = new Vue({ el: '#demo', data: { message: 'Hello V

MVVM大比拼之AngularJS源码精析

MVVM大比拼之AngularJS源码精析 简介 AngularJS的学习资源已经非常非常多了,AngularJS基础请直接看官网文档.这里推荐几个深度学习的资料: AngularJS学习笔记 作者:邹业盛 .这个笔记非常细致,记录了作者对于AngularJS各个方面的思考,其中也不乏源码级的分析. 构建自己的AngularJS .虽然放出第一章后作者就写书去了.但这第一部分已经足以带领读者深入窥探angularJS在核心概念上的实现,特别是dirty check.有愿意继续深入的读者可以去买书

2016计算机考研:数据结构常用算法精析

不知道博客园有没有计算机专业的考研党,希望列举的计算机考研考点能帮助大家吧,以下就是数据结构常用算法精析,如果大家看有什么不对的地方,欢迎纠错指正啊哈哈哈.2016考研加油!!!!!!!!! 内部排序(在内存中进行的排序不需要访问外存的)外部排序(排序量很大,通过分批的读写外存,最终完成排序) 稳定排序和非稳定排序:看相同记录的相对次序是否回发生改变.主要看在排序过程中的比较是不是相邻记录,如果是相邻比较,一定是稳定的排序.如果不是相邻的比较,就是不稳定的. 内排序方法 截止目前,各种内排序方法

绝命毒师口语精析(6)

Finally, 我们终于完成了绝命毒师第一季第一集的口语精析-- 从本期开始,就踏入!!第二集啦 我能明显感觉到,我对这部剧的热爱在一点点地被消磨-- 所以从这期开始我就每集做一期,当然每期是不可能涵括所有知识点的,我会整理下来,放在文末,希望感兴趣的童鞋自行了解,欢迎在评论区交流~ 1. dime on someone 原句:He thinks maybe you dimed on him. 每个人的青春都是相似的,相信每个班上总有那么个喜欢打小报告的人,不知道你有没有被小报告过呢? 又扯远

PS(photoshop)抠图(切图)必备快捷键及要点简析

对于PS来说,小码哥也算是初学者,懂得也仅仅是一些工作上用的最多的常用知识,大家不要鄙视鄙人哈!下面嗫,是小码哥我平时抠图(切图)时,常用的一些工具和快捷键.看似简单,但是,只要用精了,做网站页面编写完全木有问题滴,,,,嘎嘎 废话不多说了,看要点: 1.H键:鼠标光标转换为"小手"形状,此时,就能点击鼠标左键拖动图像了. 2.V键:则会把鼠标光标回复到正常的"箭头"状.用于你对右侧图层选择. 3.C键:鼠标光标直接转换成切片工具状--即一把刻刀的形状.然后就可以直

Iframe用法精析

<iframe frameborder=0 width=170 height=100 marginheight=0 marginwidth=0 scrolling=no src="move-ad.htm"></iframe> <IFRAME>用于设置文本或图形的浮动图文框或容器. BORDER <IFRAME BORDER="3"></IFRAME> 设定围绕图文框的边缘宽度 FRAMEBODER <

Knockout源代码精析-怎样解析demo元素,获取到bindings(二)?

接上文这里開始分析applyBindingsToNodeInternal.applyBindingsToNodeInternal方法例如以下: function applyBindingsToNodeInternal(node, sourceBindings, bindingContext, bindingContextMayDifferFromDomParentElement) { // Prevent multiple applyBindings calls for the same nod

精析AngularJS(一)

AngularJS简介 四个核心思想:依赖注入.模块化.双向绑定.语义化标签. AngularJS 前端 MVC 的设计与搭建 MVC(Model View Controller)模型(model)-视图(view)-控制器(controller). 用一种业务逻辑.数据.界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑.MVC被独特的发展起来用于映射传统的输入.处理和输出功能在一个逻辑的图形化用户界面的结构中. Bindi

iOS开发中的CALayer精析

一.UIView和CALayer 首先,我们来看继承关系,UIView->UIResponder->NSObject ,而CALayer直接继承自NSObject,可见在NSObject的树形模型中,CALayer比UIView层级要高,但这并不能说明什么,那么我们先来看一下CALayer的API文档中的解释. The CALayer class manages image-based content and allows you to perform animations on that c