【LeetCode刷题记录】剑指 Offer 36. 二叉搜索树与双向链表

剑指 Offer 36. 二叉搜索树与双向链表

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

为了让您更好地理解问题,以下面的二叉搜索树为例:
在这里插入图片描述
我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。

下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。
在这里插入图片描述
特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。

解题思路:
比较容易能够想到,二叉搜索树的中序遍历就是排好序的结果,然后自己在求解的时候考虑了引入额外对的数据结构,按照中序遍历的顺序存下经过的树节点,然后在遍历保存的中序序列结果,修改left和right的指向,即当前节点的 left 指向上一个节点,right 节点指向下一个节点,最后让第一个节点的 left 指向最后一个节点,最后一个节点的 right 指向第一个节点

java实现-使用辅助空间:

//借助辅助数据结构
    public static LinkedList<Node> list;
    public static void dfs(Node root){
        if(root==null) return;
        dfs(root.left);
        list.add(root);
        dfs(root.right);
    }
   public Node treeToDoublyList(Node root) {
     if(root==null) return root;
     list = new LinkedList<Node>();
     dfs(root);
     int size = list.size();
     for(int i=0;i<size;i++){
        // System.out.print(list.get(i).val+" ");
       if(i+1<size) list.get(i).right = list.get(i+1);
       if(i-1>=0) list.get(i).left = list.get(i-1);
     }
     list.get(0).left = list.get(size-1);
     list.get(size-1).right = list.get(0);
      return list.get(0);
    }

之后查看别人的解法,同样是在中序遍历的基础上,增加一个 prehead 节点,让当前遍历到的节点为 cur 的时候,pre 节点保存指向中序遍历顺序的节点 cur 的前一个节点,head 节点保存头结点,那么当中序遍历的时候即有 pre.right=cur,cur.left=pre.当中序遍历结束之后此时的 head 节点记录头部,pre 节点指向的是尾部,然后设置 head.left=pre,pre.right=head
算法流程:
1.终止条件: 当节点cur为空的时候,表示越过叶子节点,直接放回
2.递归左子树.
3.构建链表:
(1)当pre为空的时候,代表此时访问的是第一个节点,记为head.
(2)当pre不为空的时候,修改双向链表的指向,即pre.right = cur, cur.left = pre
(3)保存cur:更新pre = cur
4.递归右子树
5.构建头尾指针的指向,即head.left = pre,pre.right = head.
java实现-pre指针:

public Node head, pre;
    public  void buildList(Node root){
        if(root==null) return;
        buildList(root.left);
        if(pre!=null) pre.right = root;  //是中序遍历序列意义上的pre
        else head = root;
        root.left = pre;
        pre = root;
        buildList(root.right);

    }
      public Node treeToDoublyList(Node root) {
        if(root==null) return null;
        //先构建双向链表,最后增加头尾
        buildList(root);
        //最后一定是head到头结点,pre到尾节点
        head.left = pre;
        pre.right = head;
        return head;
   }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值