25 二叉搜索树与双向链表

Posted zqlucky

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了25 二叉搜索树与双向链表相关的知识,希望对你有一定的参考价值。

题目描述

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。
 
思路:分为循环版本和递归版本。
循环版本:
二叉搜索树的中序遍历就是递增序列,所以本题本质就是中序遍历。有两点非常需要注意:
1)开始自己认为需要对链表的首尾节点进行特殊处理,比如开始节点需要left指向nullptr,但是画个图就会非常明显,中序遍历是左中右的顺序,所以头节点是遍历到最左边的叶子节点才开始处理,此时头结点left和right指针都指向nullptr,同理尾节点也是一样的,所以不需要进行特殊处理,需要注意的时候因为最后需要返回一个头节点,所以需要一个bool变量记录第一次遍历得到的头结点保存起来,后面进行return。
2)开始自己想的是将中序遍历的结果使用一个数组保存下来,但是不需要这么做,只需要遍历的过程中,进行交换即可,一个传入的root变量,一个pre节点,
 
root -> left = pre;
pre -> right = root;
/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
public:
    TreeNode* Convert(TreeNode* pRootOfTree){
        if(pRootOfTree == nullptr){
            return nullptr;
        }
        //inorder
        stack<TreeNode*> s; 
        TreeNode* pre = nullptr;
        TreeNode* root = pre;
        bool isFirst = true;
        while(!s.empty() || pRootOfTree != nullptr){
            while(pRootOfTree != nullptr){
                s.push(pRootOfTree);
                pRootOfTree = pRootOfTree -> left;
                                
            }
            if(!s.empty()){
               pRootOfTree = s.top();
               s.pop();              
               if(isFirst){
                   isFirst = false;
                   pre = pRootOfTree;
                   root = pre;
                    
                }
                else{//举例子,最左边的最右边的节点都是叶子节点,左右都是指向null,所以不需要特殊处理
                    pre -> right = pRootOfTree;
                    pRootOfTree -> left = pre;
                    pre = pRootOfTree;
                }
               pRootOfTree = pRootOfTree -> right;
            }
        }
         
        return root;
    }
};

2、递归版本

将左子树转换为有序双向链表,然后找到左子树对应链表的最后一个节点leftLast,将leftLast和root节点连接起来,然后对右子树进行同样的处理,得到右子树对应的链表头结点是rightHead,将root和rightHead连接起来,放回结果的时候需要判断leftHead是否为空,为空的时候需要返回root。

这里关键的理解就是helper这个递归函数每次返回的是一个链表的头结点,不管是左子树还是右子树调用返回的都是对应部分的头结点。

 

/*
struct TreeNode {
    int val;
    struct TreeNode *left;
    struct TreeNode *right;
    TreeNode(int x) :
            val(x), left(NULL), right(NULL) {
    }
};*/
class Solution {
public:
    TreeNode* helper(TreeNode* root){
        if(root == nullptr){
            return nullptr;
        }
        TreeNode* leftHead = helper(root -> left);
        TreeNode* leftLast = leftHead;
        if(leftLast != nullptr){
            while(leftLast != nullptr && leftLast -> right != nullptr){//find last left node 
                leftLast = leftLast -> right;
            }
            leftLast -> right = root;
            root -> left = leftLast;
        }
        
        TreeNode* rightHead = helper(root -> right);
        if(rightHead != nullptr){
            root -> right = rightHead;
            rightHead -> left = root;
        }
        
        return (leftHead != nullptr) ? leftHead : root;
    }
    TreeNode* Convert(TreeNode* pRootOfTree){
       if(pRootOfTree == nullptr){
           return nullptr;
       } 
       return helper(pRootOfTree);
    }
};

 

 

 

 

 

 

 

 

以上是关于25 二叉搜索树与双向链表的主要内容,如果未能解决你的问题,请参考以下文章

二叉搜索树与双向链表

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

剑指offer 27:二叉搜索树与双向链表

剑指offer二十七之二叉搜索树与双向链表

剑指offer 二叉搜索树与双向链表

剑指offer 二叉搜索树与双向链表