二叉搜索树与双向链表


JZ36 二叉搜索树与双向链表(牛客网)

题目链接

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。如下图所示
在这里插入图片描述
注意:
1.要求不能创建任何新的结点,只能调整树中结点指针的指向。当转化完成以后,树中节点的左指针需要指向前驱,树中节点的右指针需要指向后继
2.返回链表中的第一个节点的指针
3.函数返回的TreeNode,有左右指针,其实可以看成一个双向链表的数据结构
4.你不用输出双向链表,程序会根据你的返回值自动打印输出

思路,在二叉树中,每个节点都有两个指向子节点的指针。在双向链表中,每个节点也有两个指针,分别指向前一个节点和后一个节点。这两种节点的结构很相似,二叉搜索树是一种排序的数据结构,它的左子节点的值总是小于父节点的值,右子节点的值总是大于父节点的值。

原先指向左子节点的指针,调整为链表中指向前一个节点的指针。
原先指向右子节点的指针,调整为链表中指向后一个节点的指针。

我们用一个具体的例子来做进一步的分析,当我们执行中序遍历到根节点的时候,就可以把树看成3部分 ①值为10的节点 ②根节点值为6的左子树 ③根节点值为14的右子树
在这里插入图片描述

根据排序链表的定义,值为10的节点将和它的左子树中的最大节点(值为8的节点)链接起来,同时它还将和右子树中最小的节点(值为12的节点)链接起来,如下图所示,将其拆成了根节点、左、右子树,我们把左子树与右子树都转换成双向链表之后再和根节点链接起来,整颗二叉搜索树也就转成了排序双向链表。
在这里插入图片描述

按照中序遍历的顺序,当我们遍历转换到根节点(值为10的节点)时,它的左子树已经转换成一个排序的链表了,并且处在链表中的最后一个节点时当前值最大的节点。我们把值为8的节点和根节点链接起来,此时链表中的最后一个节点就是10了。接着我们去遍历转换右子树,并把根节点和右子树中最小的节点链接起来。
左、右子树节点转换的过程跟遍历的过程是一样的,因此我们可以用递归来解决问题。

代码:

class Solution {
public:
    void Inorder(TreeNode* cur,TreeNode*& prev)  //采用应用可以当前节点的上一个节点
    {
    	//判空,如果为空则不需要链接
        if(cur==nullptr)return;
        Inorder(cur->left,prev);
        //当前left指向前一个
        cur->left=prev;
        //当前right指向后一个
        if(prev)prev->right=cur;
        //更新prev
        prev=cur;
        Inorder(cur->right,prev);
    }
    TreeNode* Convert(TreeNode* pRootOfTree) {
        TreeNode* prev=nullptr;
        Inorder(pRootOfTree,prev);
        TreeNode* ret=pRootOfTree;
        //要返回的节点值为最小值的节点,也就是二叉排序树的最左节点
        while(ret&& ret->left)ret=ret->left;
        return ret;
    }
};

递归展开图 6当根节点举例
在这里插入图片描述

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

题目链接

思路同上,由于此题需建立双向循环链表,所以我们只需找到二叉树搜索树的最左节点和最右节点进行首尾互连即可,因为二叉搜索树最左节点为二叉搜索树中最小元素,二叉搜索树最右节点为二叉搜索树最大节点。

代码:

class Solution {
public:
    void Inorder(Node* cur,Node*& prev)
    {
        if(cur==nullptr)return;

        Inorder(cur->left,prev);
        //当前left指向前一个
        cur->left=prev;
        //当前right指向后一个
        if(prev)prev->right=cur;
        //更新prev
        prev=cur;
        Inorder(cur->right,prev);
    }
    Node* treeToDoublyList(Node* root) {
        if(root==NULL)return NULL;
        Node* prev=nullptr;
        Inorder(root,prev);
        //首位互连部分代码
        Node* _left=root;
        while(_left&& _left->left)_left=_left->left;  //找到搜索二叉树的最左节点,就是链表的头节点
        Node* _right=root;
        while(_right&&_right->right)_right=_right->right; //找到搜索二叉树的最右节点,就是链表的尾节点
        //头节点的left指向尾节点,尾节点的right节点指向头节点
         _left->left=_right;
        _right->right=_left;
        return _left;
    }
};
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值