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

一、题目

题目链接:力扣

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

为了让您更好地理解问题,以下面的二叉搜索树为例:

我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。

下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。

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


二、题解

1、思路

🐗 深度优先--中序遍历

我竟然不知道什么是二叉搜索树!可能是忘记了,不记得之前有学过!可恶!

二叉搜索树有以下的性质

  • 若左子树不空,那左子树所有节点的值均 < 根节点的值。
  • 若右子树不空,那右子树所有节点的值均 > 根节点的值。
  • 左右子树也均为二叉搜索树。

仔细观察上面的二叉搜索树,你会发现当对二叉搜索树进行中序遍历时,得到的结果是一个有序的序列。

算法流程:

dfs(cur)函数: 递归法中序遍历;

1.终止条件: 当节点 cur 为空,代表越过叶节点,直接返回;
2.递归左子树,即 dfs(cur.left) ;
3.构建链表:

  • 当 pre 为空时: 代表正在访问链表头节点,记为 head ;
  • 当 pre 不为空时: 修改双向节点引用,即 pre.right = cur , cur.left = pre ;
  • 保存 cur : 更新 pre = cur ,即节点 cur 是后继节点的 pre ;

4.递归右子树,即 dfs(cur.right) ;

上面是力扣,讲的,你可能每太看明白。下面是我的理解:

1. 通过上面的解读,我们知道中序遍历搜索树可以获得升序排列的序列,好了,现在对于dfs函数,我们只需要知道,每次进入dfs函数访问结点,都是按照中序遍历的顺序依次访问的结点,其他就不用关心。

2. 我们只要按照要求将两个相邻结点连接即可。

3. 当然对于头节点要特殊处理,尾结点最终会保存在pre之阵中。

2、代码实现

🐗 深度优先--中序遍历

关键点:使用pre指针是否为空,当前是否是链表第一个元素。

class Solution {
public:
    Node* treeToDoublyList(Node* root) {
        if(root == NULL)return root;// 千万不要忘记,不然会报错
        dfs(root);

        // 双向链表组成双向循环链表
        head->left = pre;// 头接尾
        // 最后一个pre指向中序遍历最后一个元素
        pre->right = head;// 尾接头
        return head;
    }

private:
    Node* pre = NULL, *head;
    void dfs(Node* cur)
    {
        if(cur == NULL)return;
        dfs(cur->left);
        // 不需要关心具体怎样遍历的,只要知道两个dfs函数中间就是按照中序遍历的顺序访问结点即可

        // pre是前一个元素,搜索二叉树中序遍历为递增序列
        // 因此pre指向元素小于cur,而且两者挨着
        // pre、cur挨着,因此pre右指cur,cur左指pre
        if(pre != NULL)pre->right = cur;// 小的right指向大的
        else head = cur;// 当pre==null时,cur左侧没有节点,即此时cur为双向链表中的头节点

        // 看上面注释
        cur->left = pre;// 第一个结点指向的空

        // 更新pre
        pre = cur;
        dfs(cur->right);
    }
};

3、复杂度分析

🐗 深度优先--中序遍历

时间复杂度:O(n);

空间复杂度:O(n)。

4、运行结果

🐗 深度优先--中序遍历

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kashine

你的鼓励将是我创作的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值