【剑指offer】27 - 二叉搜索树与双向链表

题目描述

题目:输入一颗二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的节点,只能调整树中节点指针的指向。输入一颗二叉树,输出结果为转换之后的排序双向链表,如下图所示:
这里写图片描述
二叉树节点定义如下

struct TreeNode 
{
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) 
        :val(x), left(NULL), right(NULL) 
    {}
};
解题思路
  • 拿到这个题目,首先我们要考虑的是如何和将二叉搜索树与有序双向链表联系起来。二叉搜索树,每个节点有两个指针,一个指向左子树,一个指向右子树,左子树的节点值小于根节点,右子树的节点值大于根节点。所以,如果,中序遍历二叉搜索树,则遍历结果即为一个有序序列。
  • 双向链表每个节点也有两个指针,一个指向该节点的前驱,一个指向该节点的后继,若双向链表有序,则当前节点的前驱小于它,它的后继大于它。
  • 联系二叉搜索树与有序双向链表的共同点,我们可以考虑:将二叉树中序遍历的序列与有序双向链表序列对应起来,根节点为当前节点,左子树为当前节点的前驱,右子树为当前节点的后继,整个解题思路我们就理清楚了,我们以图示上述过程如下:
    二叉树看做三个部分
  • 如上图所示,我们将二叉树看做三个部分:值为10的节点,根节点为6的左子树,根节点为14的右子树,根据排序链表的定义,我们将左子树中序遍历的最后一个节点与值为10 的节点连接起来,将右子树中序遍历的第一个节点与值为10 的节点连接起来。对于左子树和右子树,我们可以将其看做子问题,按照上面所述同样的方法进行转换,由此我们可以想到使用递归的方式来解决这个问题
代码实现
  • 第一步:将左子树构造成双向链表,并且返回左子树的头结点作为双向有序链表的头结点
  • 第二步:定位至左子树的最后一个节点
  • 第三步:若左子树不为空,则将左子树的最后一个节点与当前根节点root链接起来
  • 第四步:将右子树构造成双向链表,并且返回右子树的头结点
  • 第五步:若右子树不为空,则将右子树的头结点与当前根节点root链接起来
  • 第六步:若左子树头节点为空,则返回根节点,否则返回左子树头结点
TreeNode* Convert(TreeNode* pRootOfTree)
{
    if (pRootOfTree == NULL)
        return NULL;
    if (pRootOfTree->left == NULL && pRootOfTree->right == NULL)
        return pRootOfTree;

    TreeNode* left = Convert(pRootOfTree->left);

    TreeNode* tail = left;
    while (tail != NULL && tail->right != NULL)
    {
        tail = tail->right;
    }

    if (left != NULL)
    {
        tail->right = pRootOfTree;
        pRootOfTree->left = tail;
    }

    TreeNode* right = Convert(pRootOfTree->right);

    if (right != NULL)
    {
        pRootOfTree->right = right;
        right->left = pRootOfTree;
    }

    return left == NULL ? pRootOfTree : left;
}
  • 完整实现代码:
TreeNode* Convert(TreeNode* pRootOfTree)
{
    if (pRootOfTree == NULL)
        return NULL;
    if (pRootOfTree->left == NULL && pRootOfTree->right == NULL)
        return pRootOfTree;

    TreeNode* left = Convert(pRootOfTree->left);

    TreeNode* tail = left;
    while (tail != NULL && tail->right != NULL)
    {
        tail = tail->right;
    }

    if (left != NULL)
    {
        tail->right = pRootOfTree;
        pRootOfTree->left = tail;
    }

    TreeNode* right = Convert(pRootOfTree->right);

    if (right != NULL)
    {
        pRootOfTree->right = right;
        right->left = pRootOfTree;
    }

    return left == NULL ? pRootOfTree : left;
}

//非递归版本
TreeNode* ConvertNonR(TreeNode* pRootOfTree)
{
    if (pRootOfTree == NULL)
        return NULL;
    if (pRootOfTree->left == NULL && pRootOfTree->right == NULL)
        return pRootOfTree;
    stack<TreeNode*> s;
    TreeNode* cur = pRootOfTree;
    TreeNode* pre = NULL; //中序遍历的上一个节点
    bool isFirst = true;
    while (cur != NULL || !s.empty())
    {
        //将左节点依次入栈,一直到最左节点进栈为止
        while (cur != NULL)
        {
            s.push(cur);
            cur = cur->left;
        }
        cur = s.top();
        s.pop();
        if (isFirst)
        {
            //将中序遍历的第一个节点记为root
            pRootOfTree = cur;
            pre = pRootOfTree;
            isFirst = false;
        }
        else
        {
            pre->right = cur;
            cur->left = pre;
            pre = cur;
        }
        cur = cur->right;
    }
    return pRootOfTree;
}

void PrintList(TreeNode* head)
{
    while (head != NULL)
    {
        printf("%d ->", head->val);
        head = head->right;
    }
    printf("over\n");
}

void PrintTree(TreeNode* root)
{
    if (root != NULL)
    {
        PrintTree(root->left);
        printf("%d ->", root->val);
        PrintTree(root->right);
    }
}
int main()
{
    TreeNode* node4 = new TreeNode(4);
    TreeNode* node6 = new TreeNode(6);
    TreeNode* node8 = new TreeNode(8);
    TreeNode* node10 = new TreeNode(10);
    TreeNode* node12 = new TreeNode(12);
    TreeNode* node14 = new TreeNode(14);
    TreeNode* node16 = new TreeNode(16);
    node6->left = node4;
    node6->right = node8;
    node10->left = node6;
    node10->right = node14;
    node14->left = node12;
    node14->right = node16;
    cout << "Before convert:" << endl;
    PrintTree(node10);
    printf("over\n");
    cout << "After convert:" << endl;
    TreeNode* head = Convert(node10);
    //TreeNode* head = ConvertNonR(node10);
    PrintList(head);
    return 0;
}
  • 程序运行结果:
    二叉树与链表转换结果

猜你喜欢

转载自blog.csdn.net/Aurora_pole/article/details/81352233