zoukankan      html  css  js  c++  java
  • 二叉搜索树与双向链表

    ##题目描述 输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

    思路

    关于树的深度搜索操作,一般都有递归和栈两种实现。
    此题对树进行中序遍历,在遍历过程中操作前后两个结点,所以需要pre指针。
    时间复杂度O(n),空间复杂度O(1)。

    正确的递归代码

    /**
    public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;
    
        public TreeNode(int val) {
            this.val = val;
    
        }
    
    }
    */
    public class Solution {
        private TreeNode pre;
        
        private void helper(TreeNode curr) {
            if(curr == null)    return ;
            helper(curr.left);
            curr.left = pre;
            if(pre != null) {
                pre.right = curr;
            }
            pre = curr;
            helper(curr.right);
        }
        
        public TreeNode Convert(TreeNode pRootOfTree) {
            if(pRootOfTree == null)    return null;
            helper(pRootOfTree);
            TreeNode p = pRootOfTree;
            // 类似非递归代码,设置一个成员变量可以无需循环查找
            while(p.left != null) {
                p = p.left;
            }
            return p;
        }
    }
    

    错误的递归代码

    public class Solution {
        private void helper(TreeNode pre, TreeNode curr) {
            if(curr == null)    return ;
            helper(pre, curr.left);
            curr.left = pre;
            if(pre != null) {
                pre.right = curr;
            }
            pre = curr;
            helper(pre, curr.right);
        }
        
        public TreeNode Convert(TreeNode pRootOfTree) {
            if(pRootOfTree == null)    return null;
            helper(null, pRootOfTree);
            TreeNode p = pRootOfTree;
            while(p.left != null) {
                p = p.left;
            }
            return p;
        }
    }
    

    非递归代码

    import java.util.Stack;
    /**
    public class TreeNode {
        int val = 0;
        TreeNode left = null;
        TreeNode right = null;
    
        public TreeNode(int val) {
            this.val = val;
    
        }
    
    }
    */
    public class Solution {    
        public TreeNode Convert(TreeNode pRootOfTree) {
            if(pRootOfTree == null)    return null;
            Stack<TreeNode> stack = new Stack<TreeNode>();
            TreeNode first = null;
            TreeNode p = pRootOfTree;
            TreeNode pre = null;
            while(p != null || !stack.empty()) {
                while(p != null) {
                    stack.push(p);
                    p = p.left;
                }
                p = stack.pop();
                if(pre != null) {
                    p.left = pre;
                    pre.right = p;
                    pre = p;
                } else {
                    p.left = null;
                    pre = p;
                    first = p;
                }
                p = p.right;
            }
            return first;
        }
    }
    

    笔记

    错误递归代码主要是递归携带的pre参数受到了运行时栈帧的影响,先压入的栈帧无法感知到后压入栈帧对pre的修改,所以在栈帧弹出时,后弹出的栈帧使用的依旧是旧的pre参数。但整个递归函数的运行,per参数是需要在递归每一层更新的,也就是说先入栈的栈帧将pre参数传递给后面入栈的栈帧,同时先弹出的栈帧,需要将修改后的pre同步给还未弹出的栈帧。引用传递并没有这个效果,所以虽然pre是引用传递,但每一个栈帧在运行时,使用的仍是当初保存的旧的引用。

    引用传递保证的是不同变量指向同一内存(区别于C++的引用)
    

    所以这里需要使用成员变量,使每一个栈帧操作的都是同一个pre。

  • 相关阅读:
    Hadoop之MapReduce
    Hadoop之序列化
    Hadoop之mapreduce 实例五
    Hadoop之hive和hadoop的交互流程
    protel总结1
    将正数十进制转换为2~16进制数
    基于verilog分频器总结
    MATLAB设计FIR滤波器
    centos7+hadoop完全分布式集群搭建
    Linux下常用配置文件
  • 原文地址:https://www.cnblogs.com/ustca/p/12346917.html
Copyright © 2011-2022 走看看