剑指 Offer 36. 二叉搜索树与双向链表(递归+迭代)

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

问题描述

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

“head” 表示指向链表中有最小元素的节点。

特别地,我们希望可以就地完成转换操作。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继。还需要返回链表中的第一个节点的指针。

解题思路

解法一(递归解法):

首先由于二叉搜索树本身就是有序的,因此转换为排序双向链表的时候,需要完成:把原本指向左节点的指针改变为指向上一节点,把原本指向右节点的指针改变为指向下一节点。

因为需要按照从小到大的顺序生成双向链表,基于二叉搜索树的性质,应该中序遍历。并在遍历的过程中依次改变左右指针。

当我们处理一个根节点时,说明我们已经处理完他的左子树了,并且已经生成了一个双向链表,链表的最后一个元素应该就作为当前根节点的left,并且双向的设置最后一个元素的right指针指向当前根节点。再遍历右子树。

可以发现,这个过程是重复的,所以使用递归的思路来解决会很方便。

中序遍历模板如下:

// 打印中序遍历
void dfs(Node root) {
    if(root == null) return;
    dfs(root.left); // 左
    System.out.println(root.val); // 根
    dfs(root.right); // 右
}

解法二(迭代解法):

既然是使用中序遍历,除了递归解法,肯定还有迭代解法。只需要按照上面的解题思路在迭代的模板中改动关键代码就可以。

//中序遍历迭代模板
public void inOrderTraversal(TreeNode tree) {
        Stack<TreeNode> stack = new Stack<>();
        while (tree != null || !stack.isEmpty()) {
            while (tree != null) {
                stack.push(tree);
                tree = tree.left;
            }
            if (!stack.isEmpty()) {
                tree = stack.pop();
                System.out.println(tree.val);
                tree = tree.right;
            }
        }
    }

 迭代解法即在上述迭代模板的基础上,增加改变left和right的代码。

Java代码

解法一(递归解法):

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val,Node _left,Node _right) {
        val = _val;
        left = _left;
        right = _right;
    }
};
*/
class Solution {
    Node pre,head;
    public Node treeToDoublyList(Node root) {
        if(root==null) return root;
        dfs(root);
        head.left = pre;
        pre.right = head;
        return head;

    }
    public void dfs(Node cur){
        if(cur==null) return;
        dfs(cur.left);
        if(pre!=null) pre.right = cur;
        else head = cur;
        cur.left = pre;
        pre = cur;
        dfs(cur.right);
    }
}

解法二(迭代解法):

/*
// Definition for a Node.
class Node {
    public int val;
    public Node left;
    public Node right;

    public Node() {}

    public Node(int _val) {
        val = _val;
    }

    public Node(int _val,Node _left,Node _right) {
        val = _val;
        left = _left;
        right = _right;
    }
};
*/
class Solution {
    Node pre,head;
    public Node treeToDoublyList(Node root) {
        if(root==null) return root;
        Stack<Node> st = new Stack<>();
        Node head=null,pre=null;
        Node cur = root;
        while(!st.empty() || cur!=null){
            while(cur!=null){
                st.push(cur);
                cur = cur.left;
            }
            if(!st.empty()){
                cur = st.pop();
                if(pre==null){
                    head = cur;
                } else pre.right = cur;
                cur.left = pre;
                pre = cur;
                cur = cur.right;
            }
        }
        head.left = pre;
        pre.right = head;
        return head;

    }
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值