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

本文介绍了如何利用深度优先搜索(DFS)的中序遍历策略,将二叉搜索树转化为循环双向链表,通过维护前驱节点和首尾节点,确保链表有序且形成闭环。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这道题是将一颗二叉搜索树转换为循环的双向链表。
观察后,发现可以用DFS来做。由于二叉搜索树的有序特性。可以发现,如果将整棵树按照中序遍历进行输出,得到的就是一个有序序列。因为二叉搜索树的左子树都比根节点小,右子树都比根节点大。

中序遍历下,按照 左子树 -> 根节点 -> 右子树 的顺序进行访问。
则第一个访问到的节点是整棵树最左侧的节点,也即是最小的节点。进行模拟可以发现,中序遍历得到的结果是从小到大有序的。

于是我们考虑用DFS进行中序遍历,并按照顺序连接前后的节点即可,我们需要一个pre变量,来存储前驱节点。当遍历访问当前节点时,将当前节点与前驱节点进行连接即可。另外,由于题目要求得到一个循环链表,则还需要两个变量firstlast,来记录整个链表的头节点和尾节点,在遍历完成后将这两个节点相连

(回顾后,发现可以不用pre节点,由于每次都要更新当前节点为last,其实last节点在整个过程中是和pre节点一致的,使用last节点来代替pre节点的作用即可)

代码如下

class Solution {

    Node first = null;
    Node last = null;
    Node pre = null;
    
    public Node treeToDoublyList(Node root) {
        if (root == null) return null;
        dfs(root);
        // 将first和last相连
        first.left = last;
        last.right = first;
        return first;
    }

    // 中序遍历
    private void dfs(Node node) {
        if (node == null) return;
        // 第一个没有左儿子的节点, 就是最左侧的节点, 链表的第一个节点
        if (node.left == null && first == null) first = node; 
        dfs(node.left);
        // 访问当前节点
        if (pre != null) { // 若存在前驱节点, 则相连
        // 因为是中序遍历, 是在遍历完左子树后, 再改变当前节点的左指针, 所以不会有影响
            pre.right = node;
            node.left = pre;
        }
        // 更新当前节点为前驱节点
        pre = node;
        // 用当前节点更新last节点, 一直更新下去, last最终就是最后一个被访问的节点
        last = node;
        dfs(node.right);
    }
}

在这里插入图片描述

去掉pre节点

class Solution {
    Node first = null;
    Node last = null;
    public Node treeToDoublyList(Node root) {
        if (root == null) return null;
        dfs(root);
        // 将first和last相连
        first.left = last;
        last.right = first;
        return first;
    }

    // 前序遍历
    private void dfs(Node node) {
        if (node == null) return;
        if (node.left == null && first == null) first = node; // 最左侧的节点, 第一个节点
        dfs(node.left);
        // 访问当前节点
        if (last != null) { // 若存在前驱节点, 则相连
            last.right = node;
            node.left = last;
        }
        // 更新当前节点为前驱节点
        last = node;
        dfs(node.right);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值