剑指offer 编程题(25):二叉树搜索与双向链表

题目描述

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

在二叉搜索树中,每个结点都有两个分别指向其左、右子树的指针,左子树结点的值总是小于父结点的值,右子树结点的值总是大于父结点的值。而在双向链表中,每个结点也有两个指针,它们分别指向前一个结点和后一个结点。所以这两种数据结构的结点是一致,二叉搜索树之所以为二叉搜索树,双向链表之所以为双向链表,只是因为两个指针的指向不同而已,通过改变其指针的指向来实现是完全可能的。

例如如下的二叉搜索树,
这里写图片描述
若采用中序遍历,其遍历顺序为1-2-3-4-5-6-7,通过适当的指针变换操作,可变成的双向有序链表如下:
这里写图片描述

class Solution {
public:
    TreeNode* Convert(TreeNode* pRootOfTree)
    {
        if(pRootOfTree == nullptr) return nullptr;
        TreeNode* pre = nullptr;

        convertHelper(pRootOfTree, pre);

        TreeNode* res = pRootOfTree;
        while(res ->left)
            res = res ->left;
        return res;
    }

    void convertHelper(TreeNode* cur, TreeNode*& pre)
    {
        if(cur == nullptr) return;

        convertHelper(cur ->left, pre);

        cur ->left = pre;
        if(pre) pre ->right = cur;
        pre = cur;

        convertHelper(cur ->right, pre);

    }
};
class Solution {
public:
    TreeNode* Convert(TreeNode* pRootOfTree)
    {
        if (pRootOfTree == NULL)return NULL;
        TreeNode *pointer = NULL;
        convert2List(pRootOfTree, pointer);
        while (pointer->left!=NULL)
        {
            pointer = pointer->left;
        }
        return pointer;
    }
    void convert2List(TreeNode* pRoot,TreeNode *&pointer)
    {
        if (pRoot == NULL)
        {
            return;
        }
        {
            if (pRoot->left != NULL)
            {
                convert2List(pRoot->left,pointer);
            }

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

            pointer = pRoot;
            if (pRoot->right!=NULL)
            {
                convert2List(pRoot->right, pointer);
            }
        }
    }
};

可以中序遍历,然后push到一个vector里面,再连接成链表,此方法可以实现,但是违反题目不能创建新空间的规定,属于犯规作弊


class Solution {
public:
    vector<TreeNode*> nodes;

    void tranverse(TreeNode* pRoot) {
        if (nullptr == pRoot)
            return;
        tranverse(pRoot->left);
        nodes.push_back(pRoot);
        tranverse(pRoot->right);
    }

    TreeNode* adjustTree() {
        for (int i = 0; i < nodes.size() - 1; ++i)
            nodes[i]->right = nodes[i+1];
        nodes[nodes.size()-1]->right = nullptr;
        for (int i = nodes.size() - 1; i > 0; --i)
            nodes[i]->left = nodes[i-1];
        nodes[0]->left = nullptr;
        return nodes[0];
    }

    TreeNode* Convert(TreeNode* pRoot)
    {
        if (nullptr == pRoot)
            return nullptr;
        tranverse(pRoot);
        return adjustTree();
    }
};

非递归中序遍历

void inOrder2(BinTree *root)      //非递归中序遍历  
{  
    stack<BinTree*> s;  
    BinTree *p=root;  
    while(p!=NULL||!s.empty())  
    {  
        while(p!=NULL)  
        {  
            s.push(p);  
            p=p->lchild;  
        }  
        if(!s.empty())  
        {  
            p=s.top();  
            cout<<p->data<<" ";  
            s.pop();  
            p=p->rchild;  
        }  
    }      
}  
/*
非递归中序遍历,加个指针pre记录上一次出栈值
*/
class Solution {
public:
    TreeNode* Convert(TreeNode* pRootOfTree)
    {
        TreeNode *head = NULL, *pre = NULL;//head 输出,pre记录上一次出栈值
        stack<TreeNode*> s;
        while (pRootOfTree || !s.empty())
        {
            while (pRootOfTree)
            {
                s.push(pRootOfTree);
                pRootOfTree = pRootOfTree->left;
            }
            if (!s.empty())
            {
                pRootOfTree = s.top();
                s.pop();
                if (pre != NULL)
                {
                    pre->right = pRootOfTree;
                    pRootOfTree->left = pre;
                }
                else//pre为空,表示s第一次出栈,第一次出栈值为最左值,即输出值
                    {
                    head = pRootOfTree;
                }
                pre = pRootOfTree;
                pRootOfTree = pRootOfTree->right;
            }
        }
        return head;
    }
};
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值