实现遍历构造二叉树

377 阅读3分钟

实现遍历构造二叉树:

理论可见:

关于他的代码实现:z

由前序遍历和中序遍历构造二叉树

LeetCode105. 从前序与中序遍历序列构造二叉树

解题思路

图片.png

  • 前序遍历的第一个值为根节点的值

  • 两种遍历的左右子树大小一样,因此可以在中序遍历中找到根节点的值,则其左侧即为左子树,右侧即为右子树
    此时左子树的大小已经得到,右子树的大小可以通过整个树的大小及左子树的大小运算得到

  • 递归构建左右子树即可.

时间复杂度:O(n), n为元素个数。 空间复杂度:O(n)

参考:链接

代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize){
  if(preorderSize== 0||inorderSize== 0) //前序遍历长度、中序遍历长度=0
  return NULL;

   struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode)); //申请一个二叉树root指针
   int index; //此时下标
    root -> val = preorder[0];//root指针数据指向前序遍历的第一个元素即根节点
    for(index = 0;index < inorderSize;index++)//index<中序遍历的长度 递归
      { if(inorder[index]==preorder[0]) //中序遍历里面找到根结点 左边为左子树,右边为右子树
       break; }  

 root->left=buildTree(preorder+1,index,inorder,index); 
 root->right=buildTree(preorder+index+1,preorderSize-index-1,inorder+index+1,preorderSize-index-1); 
     
      return root;
}

这里主要讲下这二句:

 root->left=buildTree(preorder+1,index,inorder,index); 
 root->right=buildTree(preorder+index+1,preorderSize-index-1,inorder+index+1,preorderSize-index-1);             

举个例子说明过程吧:

输入

  • preorder = [3,9,20,15,7]

  • inorder =[9,3,15,20,7]

    1. root -> val = preorder[0]; 前序找到根节点是3
    1. 再通过for循环找到了根节点3在中序遍历的位置 是index=1时候,第二个数组元素
    1. root->left=buildTree(preorder+1,index,inorder,index); 。左边的子树要递归的子树此时的范围是函数(下一个前序的元素,1,inorder,1) ,即preorder=[9],inorder=[9],再递归调用函数。
      等于递归左子树的了。
  • 4.比如第一次得到根节点3,index=1时候。root->right=buildTree(preorder+index+1,preorderSize-index-1,inorder+index+1,preorderSize-index-1);
    右边的子树要递归的函数(前序+index+1,前序长度5-index-1,后序+index+1, 前序长度5-index-1)
    此时前序preorder=[20,15,7],inorder=[15,20,7]。
    等于递归右子树的了。


由后序遍历和中序遍历构造二叉树

106. 从中序与后序遍历序列构造二叉树

解题思路

跟上面的一样,先通过后序找到根结点,然后再递归左右子树。

代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */

struct TreeNode* buildTree(int* inorder, int inorderSize, int* postorder, int postorderSize){
   if(postorderSize== 0||inorderSize== 0) //前序遍历长度、中序遍历长度=0
   return NULL;
   
    struct TreeNode* root = (struct TreeNode*)malloc(sizeof(struct TreeNode)); //申请一个二叉树root指针
     int index; //此时下标
    root -> val = postorder[postorderSize-1];//root指针数据指向后序遍历的最后一个元素即根节点
    
     for(index = 0;index < inorderSize;index++)//index<中序遍历的长度 递归
  { if(inorder[index]==postorder[postorderSize-1]) //中序遍历里面找到根结点 左边为左子树,右边为右子树
       break; }  

        root->left=buildTree(inorder,index,postorder,index); 
        root->right=buildTree(inorder+index+1,inorderSize-index-1,postorder+index,inorderSize-index-1); 

      return root;
}

ok,结合着第一个理解一下


由层次遍历和中序遍历构造二叉树

解题思路

  • 层序遍历序列:D A B E F C G H I

  • 中序遍历序列:E A F D H C B G I

根据层次遍历先找到根结点、在匹配中序,递归调用左右子树

比如D根结点。在中序中找到他,前面的EAF是左子树,在递归函数左子树

代码

#include<iostream>
#include<cstring>
#include<string>
using namespace std;
//因为层序是先输出根节点的,所以可以递归查找
string s1,s2;
void find(int l1,int r1,int l2,int r2)
{
    int i,j;
    for(i=l2;i<=r2;i++)//找层次遍历中优先输出根节点的位置 
    {
        int f=0;
        for(j=l1;j<=r1;j++)
        {
            if(s2[i]==s1[j])//输出根节点 
            {
                cout<<s1[j];
                f=1;
                break;
            }
        }
        if(f)//如果f不为0,说明找到了,break;
            break;
    }
    //此时DBEAC  ABCDE
    //此时跟结点A遍历中序,j=数组3位置 A  也就是l1+3 
 
    if(j>l1) //如果j>0 也就是一次一次递归,左子树结点会越来越接近0位置
        find(l1,j-1,0,r2);//遍历左子树 
    if(j<r1) //如果j<r1最大长度  也就是一次一次递归,右子树结点会越来越接近r1位置
        find(j+1,r1,0,r2);//遍历右子树 
}
int main()
{
    cin>>s1>>s2;
    find(0,s1.length()-1,0,s2.length());
    return 0;
}

参考: 问题 F: 二叉树遍历(flist)


上面基本实现了二二遍历实现构造二叉树