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

1. 描述

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的循环双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。
为了让您更好地理解问题,以下面的二叉搜索树为例:

我们希望将这个二叉搜索树转化为双向循环链表。链表中的每个节点都有一个前驱和后继指针。对于双向循环链表,第一个节点的前驱是最后一个节点,最后一个节点的后继是第一个节点。
下图展示了上面的二叉搜索树转化成的链表。“head” 表示指向链表中有最小元素的节点。

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

2. 题解

n 是 m_root 中的节点个数
时间复杂度: O(n)
空间复杂度: O(n)

十分直白的思路,一个根节点,既需要它的左子树的最右节点,即中序遍历过程中在他前边的一个节点,又需要它的右子树的最左节点,即中序遍历过程中在他后面的一个节点。那我们递归时返回什么?总不能还得写两个函数然后还得分情况讨论吧,那岂不是很麻烦?
所以我们就干脆一起返回一个已经排好序的双向链表的头部和尾部,递归返回后大家各取所需

class Solution 
{
private:
    pair<Node*, Node*> getListHeadAndTail(Node *m_root)
    {
        auto head = m_root, tail = m_root;
        if(m_root->left)
        {
            auto leftHeadTail = getListHeadAndTail(m_root->left);

            m_root->left = leftHeadTail.second;
            leftHeadTail.second->right = m_root;

            head = leftHeadTail.first;
        }

        if(m_root->right)
        {
            auto rightHeadTail = getListHeadAndTail(m_root->right);

            m_root->right = rightHeadTail.first;
            rightHeadTail.first->left = m_root;

            tail = rightHeadTail.second;
        }
    
        return {head, tail};
    }
public:
    Node* treeToDoublyList(Node *m_root) 
    {
        if(!m_root) return nullptr;

        auto headAndTail = getListHeadAndTail(m_root);
        headAndTail.first->left = headAndTail.second;
        headAndTail.second->right = headAndTail.first;

        return headAndTail.first;
    }
};
comments powered by Disqus