东寻

导航

二叉搜索树与双向链表

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

思路

关于树的深度搜索操作,一般都有递归和栈两种实现。
此题对树进行中序遍历,在遍历过程中操作前后两个结点,所以需要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。

posted on 2020-02-22 20:10  东寻  阅读(214)  评论(0编辑  收藏  举报