描述

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。如下图所示

每日一练(剑指offer)二叉搜索树与双向链表_子树


数据范围:输入二叉树的节点数 每日一练(剑指offer)二叉搜索树与双向链表_子树_02,二叉树中每个节点的值 每日一练(剑指offer)二叉搜索树与双向链表_二叉搜索树_03
要求:空间复杂度每日一练(剑指offer)二叉搜索树与双向链表_二叉搜索树_04(即在原树上操作),时间复杂度 每日一练(剑指offer)二叉搜索树与双向链表_子树_05

注意:

1.要求不能创建任何新的结点,只能调整树中结点指针的指向。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继
2.返回链表中的第一个节点的指针
3.函数返回的TreeNode,有左右指针,其实可以看成一个双向链表的数据结构

4.你不用输出双向链表,程序会根据你的返回值自动打印输出

输入描述:

二叉树的根节点

返回值描述:

双向链表的其中一个头节点。

示例

输入:

{10,6,14,4,8,12,16}

返回值:

From left to right are:4,6,8,10,12,14,16;From right to left are:16,14,12,10,8,6,4;

方法一:递归中序遍历

知识点1:二叉树递归

递归是一个过程或函数在其中定义或说明中有直接或间接调用自身的一种方法,它把一个复杂问题变成小问题进行求解。

而二叉树递归是将某个节点的左子树、右子树看成一颗完整的数,通过调用函数不断进入子树。


知识点2:二叉搜索树

二叉搜索树是一种特殊的二叉树,它的每个节点值大于它的左子节点,且大于全部左子树的节点值,小于右子树节点且小于全部右子树的节点。二叉搜索树也是一种排序结构。

思路:二叉搜索树

二叉搜索树最左端的元素一定最小,最右端的元素一定最大,符号“左中右”的特性,因此二叉搜索树的中序遍历就是一个递增序列,我们只要对它中序遍历就可以组装称为递增双向链表。

解题:

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    //返回的第一个指针,即为最小值,先定位null
    public TreeNode head=null;
    //中序遍历当前值的上一位,初值为最小值,先定位null
    public TreeNode pre=null;
    public TreeNode Convert(TreeNode pRootOfTree) {
        if(pRootOfTree==null){
            //中序递归,叶子为空则返回
            return null;
        }
        //首先递归到最左最小值
        Convert(pRootOfTree.left);
        //找到最小值,初始化head与pre
        if(pre==null){
            head=pRootOfTree;
            pre=pRootOfTree;
        }
        //当前节点与上一节点建立连接,将pre设置为当前值
        else{
            pre.right=pRootOfTree;
            pRootOfTree.left=pre;
            pre=pRootOfTree;
        }
        Convert(pRootOfTree.right);
        return head;
    }
}

方法二:非递归中序遍历

知识点:栈

栈是一种仅支持在表尾进行插入和删除的线性表,这一端被称为栈顶,另一端被称为栈低,元素入栈,是把新元素放到元素上面,变成新的栈顶元素,元素出栈是指一个元素出栈或退栈,把栈顶元素删除,使其相邻的元素成为新的栈顶元素

思路:

进行与常规的中序遍历,而且需要栈进行辅助,而且还需要增加连接节点。

解题:

import java.util.*;
public class Solution {
    public TreeNode Convert(TreeNode pRootOfTree) {
        if (pRootOfTree == null)
            return null;
        //设置栈用于遍历
        Stack<TreeNode> s = new Stack<TreeNode>(); 
        TreeNode head = null;
        TreeNode pre = null;
        //确认第一个遍历到最左,即为首位
        boolean isFirst = true; 
        while(pRootOfTree != null || !s.isEmpty()){
            //直到没有左节点
            while(pRootOfTree != null){  
                s.push(pRootOfTree);
                pRootOfTree = pRootOfTree.left;
            }
            pRootOfTree = s.pop();
            //最左元素即表头
            if(isFirst){  
                head = pRootOfTree;
                pre = head;
                isFirst = false;
            //当前节点与上一节点建立连接,将pre设置为当前值
            }else{  
                pre.right = pRootOfTree;
                pRootOfTree.left = pre;
                pre = pRootOfTree;
            }
            pRootOfTree = pRootOfTree.right;
        }
        return head;
    }
}

总结:

坚持不懈,才能持之以恒,加油🏃♂️🏃♂️