由遍历序列构造二叉树or二叉搜索树+由连续数构造二叉搜索树

由遍历序列构造二叉树or二叉搜索树+由连续数构造二叉搜索树

目录

由遍历序列构造二叉树或二叉搜索树可用递归方式求解,也可用非递归方式

递归方式的关键是定位根的左子树遍历序列与右子树遍历序列

由先序与中序遍历序列构造二叉树

问题
《由遍历序列构造二叉树or二叉搜索树+由连续数构造二叉搜索树》

递归算法:

递归函数的作用是根据先序与中序遍历序列创建二叉树,问题的关键在于定位根的左子树序列与右子树序列,分别对其调用递归函数,得到根的左子树与右子树

递归函数除需要两个遍历序列外,还需4个参数,分别为两个遍历序列的左右边界,前序序列的左边界即对应根,需建立哈希表,在中序序列中定位该根的位置,在中序序列中,根的左侧部分即为左子树序列,由此得到左子树序列的长度

前序序列中左子树序列的左界即为根的右边一个位置,右界可由之前计算的左子树序列长度得到,右子树序列左界即为左子树右界+1,右子树序列右界为前序序列右界。

中序序列中左子树左界为中序序列左界,左子树右界为根的位置-1,右子树左界为根的位置+1,右界为中序序列右界

当出现左界大于右界时,递归函数返回
或者说因为当递归函数中序列的长度为1,即只有一个节点时,其计算得到的前序序列中的左子树序列长度为0,计算得到的左子树序列左界将大于右界,计算得到的右子树序列左界也将大于右界,其调用递归函数得到左右子树时,递归函数应返回NULL,因此递归函数结束的条件为左子树序列左界大于右界

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution { 
private:
    unordered_map<int,int> table;
public:
    TreeNode* create( vector<int>& preorder,vector<int>& inorder,int pre_left,int pre_right,int in_left,int in_right )
    { 
        if( pre_left>pre_right )
            return NULL;
        TreeNode* root=new TreeNode( preorder[pre_left] );
        int pre_root=pre_left;
        int in_root=table[ preorder[pre_left] ];
        int size= in_root-in_left;
        root->left=create( preorder,inorder,pre_root+1,pre_root+size,in_left,in_root-1 );
        root->right=create( preorder,inorder,pre_root+1+size,pre_right,in_root+1,in_right );
        return root;
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { 
        int i;
        for( i=0;i<inorder.size();i++ )
        { 
            table[ inorder[i] ]=i;
        }
        return create( preorder,inorder,0,preorder.size()-1,0,inorder.size()-1 );
    }
};

非递归算法:

对于前序遍历序列中的两个连续节点u,v
只可能有两种情况,一是v是u的左孩子,这是由根左右的遍历顺序确定的,若u有左孩子,则v一定是u的左孩子;二是v是u的某祖先(或u)的右孩子,因为若u无左孩子,则下一个遍历的是u的右孩子,若u也没有右孩子,则回溯至第一个有右儿子(且 u 不在它的右儿子的子树中)的节点ua,v即为ua的右孩子

用一个栈保存当前节点的所有没有考虑过右孩子的祖先节点,用指针point指向当前节点不断往左走达到的最终节点,初始值指向中序遍历的第一个元素

首先将根节点入栈,遍历前序序列,若栈顶元素不等于point指向的元素,证明当前元素是栈顶元素的左孩子(若等于,则表明栈顶元素无左孩子),将当前元素连接为栈顶元素的左孩子并入栈;

若相等,则证明栈顶元素没有左孩子,当前元素是其祖先(或自己)的右孩子,为找到它是谁的右孩子,需比较栈中元素与中序序列。

若中序序列中没有混入某节点的右孩子,则其节点顺序与退栈顺序是一致的,当出现中序序列某节点与栈顶节点不一致时,说明刚刚退栈的节点在中序序列中引入了它的右孩子

若栈顶元素等于point指向的元素,将其退栈并暂存,point指向下一个元素,不断进行该操作直至栈顶元素与point指向的元素不等或栈为空,刚刚退栈的节点的右孩子即为现在在前序序列中遍历到的节点,将当前遍历到的节点连接并入栈

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution { 
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { 
        if( preorder.size()==0 )
            return NULL;
        stack<TreeNode*> s;
        TreeNode* root=new TreeNode( preorder[0] );
        s.push( root );
        TreeNode* p;
        int point=0;
        int i;
        for( i=1;i<preorder.size();i++ )
        { 
            if( s.top()->val!=inorder[point] )
            { 
                TreeNode* newnode=new TreeNode( preorder[i] );
                s.top()->left=newnode;
                s.push( newnode );
            }
            else
            { 
                while( !s.empty() && s.top()->val==inorder[point] )
                { 
                    p=s.top();
                    s.pop();
                    point++;
                }
                TreeNode* newnode=new TreeNode( preorder[i] );
                p->right=newnode;
                s.push( newnode );
            }
        }
        return root;
    }
};

由中序与后序序列构造二叉树

《由遍历序列构造二叉树or二叉搜索树+由连续数构造二叉搜索树》

递归算法与由前、中序构建相似,只是边界的计算稍有不同

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution { 
private:
    unordered_map<int,int> table;
public:
    TreeNode* create( vector<int>& inorder,vector<int>& postorder,int in_left,int in_right,int post_left,int post_right )   
    { 
        if( post_left>post_right )
            return NULL;
        int post_root=post_right;
        int in_root=table[ postorder[ post_right ] ];
        int size=in_root-in_left;
        TreeNode* root=new TreeNode( postorder[ post_right ] );
        root->left=create( inorder,postorder,in_left,in_root-1,post_left,post_left+size-1 );
        root->right=create( inorder,postorder,in_root+1,in_right,post_left+size,post_root-1 );
        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) { 
        int i;
        for( i=0;i<inorder.size();i++ )
            table[ inorder[i] ]=i;
        return create( inorder,postorder,0,inorder.size()-1,0,postorder.size()-1 );
    }
};

由前序与后序序列构造二叉树

《由遍历序列构造二叉树or二叉搜索树+由连续数构造二叉搜索树》

由前序与后序序列无法唯一确定一颗二叉树,但是能确定的是根的位置为前序序列的左界以及后序序列的右界,根的左子树的根为前序序列左界+1,需在后序序列中找到它的位置,因为其在后序序列中的位置为左子树后序序列的右界,因此可以计算得到左子树序列的长度

需要注意的是,当前序序列中只有一个元素时,用哈希表查找其左子树根是不能进行的,因此除左界大于右界外,需加上一个递归函数返回条件为左界等于右界,在此种情况下直接构建根节点并返回

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */
class Solution { 
private:
    unordered_map<int,int> table;
public:
    TreeNode* create( vector<int>& pre,vector<int>& post,int pre_left,int pre_right,int post_left,int post_right )
    { 
        if( pre_left>pre_right  )
            return NULL;
        if( pre_left==pre_right )
        { 
            TreeNode* root=new TreeNode( pre[ pre_left ] );
            return root;
        }
        int pre_root=pre_left;
        int post_root=post_right;
        int pre_ll=pre_root+1;
        int post_lr=table[ pre[ pre_ll ] ];
        int size=post_lr-post_left+1;  
        TreeNode* root=new TreeNode( pre[ pre_left ] );
        root->left=create( pre,post,pre_root+1,pre_root+size,post_left,post_left+size-1 );
        root->right=create( pre,post,pre_root+size+1,pre_right,post_left+size,post_root-1 );
        return root;
    }
    TreeNode* constructFromPrePost(vector<int>& pre, vector<int>& post) { 
        int i;
        for( i=0;i<post.size();i++ )
        { 
            table[ post[i] ]=i;
        }
        return create( pre,post,0,pre.size()-1,0,post.size()-1 );
    }
};

由前序序列构建二叉搜索树

《由遍历序列构造二叉树or二叉搜索树+由连续数构造二叉搜索树》
上下界的计算方式发生改变,右子树先序序列左界位置为第一个大于根节点的元素

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */
class Solution { 
public:
    TreeNode* create( vector<int>& preorder,int left,int right )
    { 
        if( left>right )
            return NULL;
        int pre_root=left;
        TreeNode* root=new TreeNode( preorder[left] );
        int i=pre_root+1;
        int size;
        while( i<=right && preorder[i]<preorder[left] )
        { 
            i++;
        }
        size=i-1-left;
        root->left=create( preorder,pre_root+1,pre_root+size );
        root->right=create( preorder,pre_root+size+1,right );
        return root;   
    }
    TreeNode* bstFromPreorder(vector<int>& preorder) { 
        return create( preorder,0,preorder.size()-1 );
    }
};

由连续数构造二叉搜索树

《由遍历序列构造二叉树or二叉搜索树+由连续数构造二叉搜索树》
左子树序列右界即为根位置-1,右子树序列左界即为根位置+1
在连续数数组中,每个元素都可为根,因此递归函数中包含对数组元素的遍历,所得到的是二叉搜索树的集合

对左子树序列以及右子树序列调用递归函数得到的也是左右子树集合,因此需分别从两个集合中取一个,与根节点组成完整的二叉搜索树,并保存

/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */
class Solution { 
public:
    vector<TreeNode*> create( int left,int right )
    { 
        if( left>right )
            return { NULL};
        int i;
        vector<TreeNode*> allcombine;
        for( i=left;i<=right;i++ )
        { 
            vector<TreeNode*> leftall=create( left,i-1 );
            vector<TreeNode*> rightall=create( i+1,right );
            for( auto x:leftall )
                for( auto y:rightall )
                { 
                    TreeNode* newnode=new TreeNode( i );
                    newnode->left=x;
                    newnode->right=y;
                    allcombine.push_back( newnode );
                }
        }
        return allcombine;
    }
    vector<TreeNode*> generateTrees(int n) { 
        if( n<1 )
            return { };
        return create( 1,n );
    }
};
    原文作者:小灵宝
    原文地址: https://blog.csdn.net/qq_44709990/article/details/107665358
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞