剑指offer:二叉搜索树转换成一个排序的双向链表

剑指offer有时候不稳定,会报错失误,空一个小时,或重启电脑,退出浏览器清空缓存。重新编译即可。

题目描述

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

class Solution {
public:
    TreeNode* Convert(TreeNode* pRootOfTree)
    {
        if(pRootOfTree == nullptr) return nullptr;
        TreeNode* pre = nullptr;
         
        convertHelper(pRootOfTree, pre);
         
        TreeNode* res = pRootOfTree;
        while(res ->left)
            res = res ->left;
        return res;
    }
     
    void convertHelper(TreeNode* cur, TreeNode*& pre)
    {
        if(cur == nullptr) return;
         
        convertHelper(cur ->left, pre);
         
        cur ->left = pre;
        if(pre) pre ->right = cur;
        pre = cur;
         
        convertHelper(cur ->right, pre);
         
         
         
    }
};

问题:对于cur ->left 和pre ->right的修改会不会影响之后的遍历?

不会,因为之前已经把上一个节点压栈保存了。

思路分析:用pre这一临时变量记录了中序遍历序列中的前一个visit的接点,然后将pre与currentNode相链接。注意双循环链表最左节点没有left,最右节点没有right。

易错点如下,记录的是中序遍历的前驱节点,而不是中序遍历序列的前驱节点。

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

错误方法,该方法只能输出部分序列,原因是递归调用参数有问题,不能把pre放进参数里面,否则回溯时会回溯以前的pre,因为引用在变化,而不是中序遍历的上一个节点。

也就是说如果对参数列表中的引用做了修改,那么它还是不适合放入参数列表中。

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

 正确解法: 

//用一个局部变量记录二叉树中序遍历的上一个访问的节点,并设置其right域。
public class Solution {
    public  TreeNode pre = null;
    public void convert(TreeNode curr){
        if(curr == null)    return ;
        convert(curr.left);
        if(pre != null) pre.right = curr;
        curr.left = pre;
        pre = curr;
        convert(curr.right);
    }
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree == null) return null;
        convert(pRootOfTree);
        while(pRootOfTree.left != null) pRootOfTree = pRootOfTree.left;
        return pRootOfTree;
    }
}

什么时候要将变量放在递归的参数列表中,“希望递归遍历时变量能还原到当初访问的时候的值”的情况下才将变量放进参数。

以后搜算法题csdn搜,百度搜不到隐藏的好答案

猜你喜欢

转载自blog.csdn.net/raylrnd/article/details/82827550