五分钟玩转面试考点-数据结构-二叉树转化为链表(破坏-遍历)

引子:五分钟玩转面试考点-数据结构系列,不会像那种严肃、古板的教科书般的博客文章,而是将晦涩难懂的概念和知识点尽可能幽默的细说出来,或结合生活场景,或从零开始分析。带给大家一个严肃而不失风趣的数据结构。五分钟玩转面试考点-数据结构-目录


中序遍历破坏树结构,那么应该保证右子树不被破坏;
后序遍历破坏树结构,那么可以保证左右子树均可破坏;

二叉树结构中直接操纵指针,让其由二叉树转化为链表结构。

面试题:给定一个二叉树,原地将它展开为链表。

将二叉树展开

小胖OS:原地算法,厉害啦!那么额外空间复杂度应该是O(1)

分析过程:
对树的操纵一般建立在遍历算法之上的。并且还要原地转换。是在树中,直接破坏树结构。我们观察,二叉树转换为了右子树,并且结构是根 左 右。是使用前序遍历吗???

为什么选用后序遍历:
转换成链表结构,是破坏整个树为前提的。

  1. 使用前序遍历,只访问根的时候,修改结构,不能修改根左边右边的指针
  2. 使用中序遍历,访问根和左子树后修改结构,不能修改根右边的指针
  3. 使用后序遍历,访问完毕左右子树和根节点,可以修改左右子树的指向(不会丢失)。

那如何操作指针?
现左子树调整为根节点的现右子树,将原左子树置空,原右子树拼接到现右子树的最后一个节点上。

  //二叉树原地转化为链表
    public static void flatten(TreeNode root) {
        //递归出口
        if (root == null) {
            return;
        }
        //后序遍历,操作根
        flatten(root.left);
        flatten(root.right);
        //第三次拿到根之后。
        //判断根节点是否含有左子树
        if (root.left != null) {
            //1、保存原右子树节点
            TreeNode temp = root.right;
            //2、root的左子树移到右子树上
            root.right = root.left;
            //3、左子树置空
            root.left = null;
            //4、将原右子树拼接到新右子树的最后一个节点上
            TreeNode newRight = root.right;
            while (newRight.right != null) {
                newRight = newRight.right;
            }
            //5、将原右子树拼接到新右子树上
            newRight.right = temp;
        }
    }

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

小胖:不能创建新的节点是不能new,但是可以改变对象的引用。比如:TreeNode temp=root.right;不是创建对象

分析:

  1. 二叉搜索树转化为有序链表,那么只能中序遍历二叉树。
  2. 不能创造新的节点,所以要在原树结构修改树结构。
  3. 如何创建新的链表?那么就需要保存尾指针,将新的节点尾节点建立关系。实时修改尾节点的位置。
  4. 树结构已经被修改了,那么(敲黑板,划重点),我们只是中序遍历遍历了左子树根节点,若是修改root.right=XXX就会将右子树丢失。故root只能操作左子树

正确代码和错误代码:

//                    tail.right = node; //正确代码
//                    node.left = tail;   //正确代码
                    tail.left = node;  //错误代码
                    node.right = tail;  //错误代码

源码:

 //二叉搜索树---》有序循环列表(中序遍历,栈实现吧)
    public TreeNode Convert(TreeNode pRootOfTree) {
        if (pRootOfTree == null) {
            return null;
        }
        //声明栈
        Stack stack = new Stack<>();
        //声明引用
        TreeNode head = null;  //头指针
        TreeNode tail = null;   //尾指针

        while (pRootOfTree != null || !stack.empty()) {
            //左子树入栈
            while (pRootOfTree != null) {
                stack.push(pRootOfTree);
                pRootOfTree = pRootOfTree.left;
            }
            //出栈,循环链表
            if (!stack.empty()) {
                //根节点出栈
                TreeNode node = stack.pop(); //创造一个新的引用
                if (head == null) {
                    head = tail = node;  //当前节赋值给头结点和尾节点
                } else {
                    //我们也是破坏这个树结构吗?
                    tail.right = node;
                    node.left = tail;
                    //尾指针前进一位
                    tail = node;
                }
                pRootOfTree = node.right;
            }
        }
        return head;
    }

你可能感兴趣的:(五分钟玩转面试考点-数据结构-二叉树转化为链表(破坏-遍历))