学习笔记之使用前序遍历和中序遍历构造二叉树

总结一下学习笔记:

一、提出问题

给出一棵树的前序遍历和中序遍历,构造二叉树,你可以假设这棵树中不存在重复的数。

例如:给出前序和中序遍历序列:preorder = [3,9,20,15,7],inorder=[9,3,15,20,7]
得到如下所示的二叉树:
在这里插入图片描述

二、解决方法

如何去遍历这棵树?
通常有两种方式去遍历,即Breadth First Search(BFS):广度优先搜索、Depth First Search(DFS):深度优先搜索。

三、概念区分

在解释BFS和DFS概念之前,先来区分一下图和树的区别。
1、什么是图?
答: 图由顶点(vertex,node)和边(edge)组成。顶点就是代表对象,因为有时候题不会直接给顶点,而是某种对象,直接看成顶点即可。我们使用链接两顶点之间的线段来表示。顶点的集合V,边的集合是E,所以图记为G = (V,E), 连接两点u和v的边用e=(u,v)表示。

在这里插入图片描述

2、什么是树?
答:树也是由一组顶点(vertex)以及若干条边(edge)组成。类似于一般的图,区别在于:树是连通的无环图。

在这里插入图片描述

3、图的遍历和树的遍历
图的遍历:包括广度优先遍历(BFS)、深度优先遍历DFS。
树的遍历:包括前序、中序、后序、层次遍历等。

图的遍历:从图的某一点出发访问其余顶点,且使得每一个顶点仅仅被访问一次,这过程叫图的遍历。

树的遍历:
1)、前序、中序、后序遍历,其实都采用的是DFS思想,DFS思想常用递归实现。
2)、层次遍历,采用的是BFS思想,采用队列这种数据结构实现。

四、算法思想

1、BFS算法思想
类似于树的层次遍历,遍历顺序从树的顶端一直遍历到底部,顶部的节点比底部的节点要优先被访问到。

2、DFS算法思想
类似于树的前、中、后序遍历,这个策略中,我们采用深度优先作为优先级,即沿着根节点一直遍历到某个叶节点,然后再返回根节点,访问其他的分支。根据根节点、左节点、右节点的顺序,DFS可以分为前序、中序、后序遍历。

下面四幅图表示了DFS和BFS的访问顺序。
从左到右依次解释:
下图一:DFS的后序遍历,节点访问顺序(L—>R—>V),即先访问左孩子,再访问右孩子、最后访问父节点,访问顺序:(1,2,3,4,5)。
下图二:DFS的前序遍历,节点访问顺序(V—>L—>R),即先访问父节点,再访问左孩子,最后访问右孩子,访问顺序(1,2,3,4,5)。
下图三:DFS的中序遍历,节点访问顺序(L—>V—>R),即先访问左孩子,再访问父节点,最后访问右孩子,访问顺序(1,2,3,4,5)。
下图四:BFS的层次遍历,访问顺序:从左到右,从上到下依次访问,访问顺序(1,2,3,4,5)。

在这里插入图片描述
下面介绍由前序遍历和中序遍历构造一棵二叉树的实现方式。

五、代码实现

1、动画展示实现思想:
在这里插入图片描述

2、代码实现:
1)、Java版本

// Definition for a binary tree node.
public class TreeNode {
  int val;
  TreeNode left;
  TreeNode right;

  TreeNode(int x) {
    val = x;
  }
}

import javafx.util.Pair;
class Solution {
  public Pair<TreeNode, int []> helper(int[] preorder, int[] inorder) {
    if (inorder.length == 0) {
      return new Pair(null, preorder);
    }

    // pick up the first element as a root
    int root_val = preorder[0];
    TreeNode root = new TreeNode(root_val);

    // find index of root in the inorder list
    int index = 0;
    for (; (index < inorder.length) && (inorder[index] != root_val); index++){}
    preorder = Arrays.copyOfRange(preorder, 1, preorder.length);

    // root splits inorder list
    // into left and right subtrees        
    int [] left_inorder = Arrays.copyOfRange(inorder, 0, index);
    int [] right_inorder = index + 1 <= inorder.length ? 
      Arrays.copyOfRange(inorder, index + 1, inorder.length) : new int [0];

    // recursion
    Pair<TreeNode, int []> p = helper(preorder, left_inorder);
    root.left = p.getKey();
    preorder = p.getValue();
    p = helper(preorder, right_inorder);
    root.right = p.getKey();
    preorder = p.getValue();

    return new Pair(root, preorder);
  }

  public TreeNode buildTree(int[] preorder, int[] inorder) {
    Pair<TreeNode, int []> result = helper(preorder, inorder);
    return result.getKey();
  }
}

2)、Python版本

# Definition for a binary tree node.
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None
        
from collections import deque
class Solution:
    def buildTree(self, preorder, inorder):
        """
        :type preorder: List[int]
        :type inorder: List[int]
        :rtype: TreeNode
        """
        def helper(preorder, inorder):
            if not inorder:
                return None
            
            # pick up the first element as a root
            root_val = preorder.popleft()
            root = TreeNode(root_val)

            # root splits inorder list
            # into left and right subtrees
            index = inorder.index(root_val)

            # recursion 
            root.left= helper(preorder, inorder[:index])
            root.right = helper(preorder, inorder[index + 1:])
            return root
        
        return helper(deque(preorder), inorder)

3)、C++实现版本

#include "stdafx.h"
#include<vector>
#include<iostream>
#include<string>
using namespace std;
struct TreeNode
{
	int val;
	TreeNode *left;
	TreeNode *right;
	TreeNode(int x) :val(x), left(NULL), right(NULL) {}
};
class Solution
{
	TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder)
	{
		return builTreeHelper(preorder, 0, preorder.size(), inorder, 0, inorder.size());
	}

	TreeNode* builTreeHelper(vector<int>& preorder, int sp, int ep, vector<int>& inorder, int si, int ei) {
		if (sp == ep) return nullptr;
		TreeNode* root = new TreeNode(preorder[sp]);
		int dis = find(inorder.begin() + si, inorder.begin() + ei, preorder[sp]) - inorder.begin() - si;
		root->left = builTreeHelper(preorder, sp + 1, sp + 1 + dis, inorder, si, si + dis);
		root->right = builTreeHelper(preorder, sp + 1 + dis, ep, inorder, si + dis + 1, ei);
		return root;
	}
};

int main()
{
  //可自行添加测试代码
	return 0;
}

六、算法复杂度分析

1、时间复杂度:O(N)
2、空间复杂度:O(N)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值