构建二叉树模板大全

 

 

目录

前言:

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

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

根据前序和后序遍历构造二叉树

构造二叉搜索树

一.概念

中序遍历数组构造二叉树

后续遍历数组构造二叉搜索树

 前序遍历数组构造二叉搜索树

总结:


前言:

有许多关于构建二叉树的题目,并且这些题目有固定的模板,我将对这类题目将进行分类总结。本篇致力于让读者能够融会贯通,抓住要领,建立模板化思维,看见一题想到一类。

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

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

根据题目来进行分析,我们拿到的条件是

后序数组: 我们知道后序数组的最后一位就是当前二叉树的根节点。

中序数组: 我们得知根据根节点可以将数组分为两部分,左边用来构造左子树,右边用来构造右子树。

综合分析:后序数组用来确定根节点,中序数组用来不断的划分左子树,右子树。

过程: 我们将两个数组并排放置,我们从后序数组中取出当前根节点,让后从中序数组中找到该根节点,以此为中心分别划分出来左区间,和右区间。再递归构造左子树和右子树

递归:

       1.确定函数返回类型:根据题目可以知道,需要返回的是TreeNode* 。

       2.确定终止条件:如果数组的长度为零的时候,返回NULL。如果数组长度为1的时候返回新创建的节点。

(有人会问:为什么这里终止条件有两个?一个是长度为零,一个是长度为一,按照做题经验来说一般不是直接拿空节点作为终止条件么?)

解答:这个问题确实思考的比较深入。终止条件怎么能写两个捏???很多讲递归的老师都会模棱两可的说因为就剩一个节点了,所以要返回。 那你把这当终止条件你要我空节点干嘛??

小伙伴们不要着急,请看如下

 其实如果不加第二个终止条件效率会变很低,但仍然可以解出来。假如我发现长度为一的数组后,我就没必要再判断NULL节点了。所以其实是用来提高效率的。 

    3.最后一层递归条件:找到后序数组最后一个元素在中序数组的位置,作为切割点切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组切割后序数组)切成后序左数组和后序右数组递归处理左区间和右区间。

代码如下:

确定终止条件

        if(postorder.size()==0) return nullptr;
        TreeNode* element=new TreeNode(postorder[postorder.size()-1]);
        if(postorder.size()==1) return element;

这里先判断数组长度是不是为零,让后再创建新节点,最后再附加一条判断数组长度是不是一。

分割数组

        int i=0;
        for(;i<inorder.size();i++)
        {
            if(inorder[i]==postorder[postorder.size()-1])
            {
                break;
            }
        }
        vector<int> in_ord_first(inorder.begin(),inorder.begin()+i);
        vector<int> in_ord_second(inorder.begin()+i+1,inorder.end());

        postorder.resize(postorder.size()-1);

        vector<int> pos_ord_first(postorder.begin(),postorder.begin()+in_ord_first.size());
        vector<int> pos_ord_second(postorder.begin()+in_ord_first.size(),postorder.end());

 分割中序数组,先在中序数组中找到根节点。定位到根节点的下标以后,将数组进行分割,创建新的数组vector<int> in_ord_first 和 vector<int> in_ord _second 。要注意区间的开闭问题,记住通过迭代器构造的都是左闭右开。

让后思考,后序数组如何分割??第一步先除去根元素 postorder.resize(postorder.size()-1);

然后通过并排对比发现,此时有一个很重的点,就是中序数组大小一定是和后序数组的大小相同的(这是必然)中序数组我们都切成了左中序数组和右中序数组了,那么后序数组就可以按照左中序数组的大小来切割,切成左后序数组和右后序数组。

vector<int> pos_ord_first(postorder.begin(),postorder.begin()+in_ord_first.size());
vector<int> pos_ord_second(postorder.begin()+in_ord_first.size(),postorder.end());

 最后一层递归条件:我们最后只需要把已经构建好的左子树,和已经构建好的右子树返回给element节点即可,然后返回element 根节点。

        element->left=buildTree(in_ord_first,pos_ord_first);
        element->right=buildTree(in_ord_second,pos_ord_second);
        return element;

(ps:递归如果看的不太懂,看我博客递归统一化模板

整体代码如下:

class Solution {
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if(postorder.size()==0) return nullptr;
        TreeNode* element=new TreeNode(postorder[postorder.size()-1]);
        if(postorder.size()==1) return element;

        int i=0;
        for(;i<inorder.size();i++)
        {
            if(inorder[i]==postorder[postorder.size()-1])
            {
                break;
            }
        }
        vector<int> in_ord_first(inorder.begin(),inorder.begin()+i);
        vector<int> in_ord_second(inorder.begin()+i+1,inorder.end());

        postorder.resize(postorder.size()-1);
        vector<int> pos_ord_first(postorder.begin(),postorder.begin()+in_ord_first.size());
        vector<int> pos_ord_second(postorder.begin()+in_ord_first.size(),postorder.end());

        
        element->left=buildTree(in_ord_first,pos_ord_first);
        element->right=buildTree(in_ord_second,pos_ord_second);
        return element;
    }
};

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

题目:105. 从前序与中序遍历序列构造二叉树

根据题目来进行分析,我们拿到的条件是

前序数组: 我们知道前序数组的第一位就是当前二叉树的根节点。

中序数组: 我们得知根据根节点可以将数组分为两部分,左边用来构造左子树,右边用来构造右子树。

综合分析:后序数组用来确定根节点,中序数组用来不断的划分左子树,右子树。

过程: 我们将两个数组并排放置,我们从后序数组中取出当前根节点,让后从中序数组中找到该根节点,以此为中心分别划分出来左区间,和右区间。再递归构造左子树和右子树

递归:

       1.确定函数返回类型:根据题目可以知道,需要返回的是TreeNode* 。

       2.确定终止条件:如果数组的长度为零的时候,返回NULL。如果数组长度为1的时候返回新创建的节点。

      3.最后一层递归条件:找到前序数组第一个元素在中序数组的位置,作为切割点切割中序数组,切成中序左数组和中序右数组 (顺序别搞反了,一定是先切中序数组切割前序数组)切成前序左数组和前序右数组递归处理左区间和右区间。

整体代码如下:

class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.size()==0) return nullptr;
        TreeNode* element=new TreeNode(preorder[0]);
        if(preorder.size()==1) return element;

        int i=0;
        for(;i<inorder.size();i++)
        {
            if(inorder[i]==preorder[0]) break;
        }
        vector<int> in_ord_first(inorder.begin(),inorder.begin()+i);
        vector<int> in_ord_second(inorder.begin()+i+1,inorder.end());

        vector<int> new_preorder(preorder.begin()+1,preorder.end());
        vector<int> pre_ord_first(new_preorder.begin(),new_preorder.begin()+in_ord_first.size());
        vector<int> pre_ord_second(new_preorder.begin()+in_ord_first.size(),new_preorder.end());

        element->left=buildTree(pre_ord_first,in_ord_first);
        element->right=buildTree(pre_ord_second,in_ord_second);
        return element;
    }
};

根据前序和后序遍历构造二叉树

题目:889. 根据前序和后序遍历构造二叉树

思路

前序遍历为:

    (根结点) (前序遍历左分支) (前序遍历右分支)

而后序遍历为:

    (后序遍历左分支) (后序遍历右分支) (根结点)

例如,如果最终的二叉树可以被序列化的表述为 [1, 2, 3, 4, 5, 6, 7],那么其前序遍历为 [1] + [2, 4, 5] + [3, 6, 7],而后序遍历为 [4, 5, 2] + [6, 7, 3] + [1].

如果我们知道左分支有多少个结点,我们就可以对这些数组进行分组,并用递归生成树的每个分

这道题跟前两个思路大同小异。

递归:

       1.确定函数返回类型:根据题目可以知道,需要返回的是TreeNode* 。

       2.确定终止条件:如果数组的长度为零的时候,返回NULL。如果数组长度为1的时候返回新创建的节点。

      3.最后一层递归条件:找到前序数组第个元素在后序数组的位置,作为切割点切割后序数组,切成后序左数组和中序右数组 (顺序别搞反了,一定是先切后序数组切割前序数组)切成后序左数组和后序右数组递归处理左区间和右区间。

代码如下:

class Solution {
public:
    TreeNode* constructFromPrePost(vector<int>& preorder, vector<int>& postorder) {
        if(preorder.size()==0) return nullptr;
        TreeNode* element=new TreeNode(preorder[0]);
        if(preorder.size()==1) return element;

        postorder.resize(postorder.size()-1);
        int i=0;
        for(;i<postorder.size();i++)
        {
            if(postorder[i]==preorder[1]) break;
        }
        vector<int> pos_ord_first(postorder.begin(),postorder.begin()+i+1);
        vector<int> pos_ord_second(postorder.begin()+i+1,postorder.end());

        vector<int> new_preorder(preorder.begin()+1,preorder.end());
        vector<int> pre_ord_first(new_preorder.begin(),new_preorder.begin()+pos_ord_first.size());
        vector<int> pre_ord_second(new_preorder.begin()+pos_ord_first.size(),new_preorder.end());

        element->left=constructFromPrePost(pre_ord_first,pos_ord_first);
        element->right=constructFromPrePost(pre_ord_second,pos_ord_second);
        return element;

    }
};

构造二叉搜索树

一.概念

二叉搜索树又称二叉排序树,具有以下性质:

    若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
    若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
    它的左右子树也分别为二叉搜索树

 请牢牢的记住这句话:中序遍历二叉搜索树等于遍历有序数组。

中序遍历数组构造二叉树

题目:108. 将有序数组转换为二叉搜索树

 当我们遍历有序数组时候,他的中间值就是根节点。所以我们每次都取数组的中间值当根节点,同时该数组一分为二变为左数组,右数组,不断重复该过程,直到数组的大小为零即构建完成。

class Solution {
private:
    TreeNode* traversal(vector<int>& nums, int left, int right) {
        if (left > right) return nullptr;
        int mid = left + ((right - left) / 2);
        TreeNode* root = new TreeNode(nums[mid]);
        root->left = traversal(nums, left, mid - 1);
        root->right = traversal(nums, mid + 1, right);
        return root;
    }
public:
    TreeNode* sortedArrayToBST(vector<int>& nums) {
        TreeNode* root = traversal(nums, 0, nums.size() - 1);
        return root;
    }
};

因为每一个过程都是相同的,所以符合递归性质。

left 和 right 用于控制每个新数组的大小,当left>right 时代表数组的大小为0递归结束。

所以终止条件是left>right.

操作过程: 创建新的节点 new TreeNode (nums[mid])。

最后一层递归条件:root 左子树结果返回给根节点。 root->left = traversal(nums, left, mid - 1);

                                root 右子树结果返回给根节点。 root->right = traversal(nums, mid+1,right);

这里着重强调一下边界条件:

因为traveral(nums,left,right) 是【  left  ,right 】 是左闭右闭。所以每次划分得抛去mid 。

不清楚递归的可以看我的这篇博客     递归统一化模板_Revenge2322的博客-CSDN博客

后续遍历数组构造二叉搜索树

后续遍历数组特点:最后一个节点是root根节点

 然后我们需要找到分界点mid ,分界点mid其实是从后往前找第一个小于5的数的下标。

将剩下的划分为左数组,和右数组,左边数组接在root->left上

右边数组接在root->right上。

TreeNode* traversal(vector<int>& nums,int left ,int right) {
    if(left>right) return nullptr;
    TreeNode* root=new TreeNode(nums[right]);
    int mid=right;
    for(int i=left;i<right;i++)
    {
        if(nums[right]<=nums[i])
        {
            mid=i;
            break;
        }
    }
    root->left=traversal(nums,left,mid-1);
    root->right=traversal(nums,mid,right-1);
    return root;
    }

 前序遍历数组构造二叉搜索树

题目:1008. 前序遍历构造二叉搜索树

 
   TreeNode* traversal(vector<int>& nums,int left ,int right) {
       if(left>right) return nullptr;
       TreeNode* root=new TreeNode(nums[left]);
       int mid=left;
       for(int i=right;i>left;i--)
       {
           if(nums[i]<=nums[left])
           {
               mid=i;
               break;
           }
       }
       root->left=traversal(nums,left+1,mid);
       root->right=traversal(nums,mid+1,right);
       return root;
   } 
 

这个跟后序数组构造二叉搜索树思路一样,不再重复。

总结:

构造二叉树一般分为构造普通的二叉树,和构造二叉搜索树。 构造二叉树我们学会一种思想,就是第一步先找当前根节点看哪一个数组能够明确确定根节点。第二步划分左区间,右区间。这里需要考察的是对vector的掌握,明确左开右闭,并且如何拷贝,如何resize。

二叉搜索树的构建,也是先寻找当前根节点。只不过这里是对一个vector进行操作,反而更加简单了,但是同样要注意区间开闭,这里没有对vector进行修改,而是用下标left,right代替划分区间,所以是左闭右闭。

更为震撼的是二叉搜索树的构建,以后将有更大的作用。欢迎看续集

二叉搜索树统一化解题模板_Revenge2322的博客-CSDN博客

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 我可以为你提供一个Python实现的二叉树模板:class TreeNode: """定义一个二叉树的节点""" def __init__(self, val): self.val = val self.left = None # 左子树 self.right = None # 右子树def preorder_traverse(root): """先序遍历二叉树""" if root == None: return print(root.val) preorder_traverse(root.left) preorder_traverse(root.right)def inorder_traverse(root): """中序遍历二叉树""" if root == None: return inorder_traverse(root.left) print(root.val) inorder_traverse(root.right)def postorder_traverse(root): """后序遍历二叉树""" if root == None: return postorder_traverse(root.left) postorder_traverse(root.right) print(root.val) ### 回答2: 下面是用Python写的一个二叉树模板,并附有中文注释: ```python class TreeNode: def __init__(self, val=0, left=None, right=None): self.val = val # 当前节点的值 self.left = left # 当前节点的左子节点 self.right = right # 当前节点的右子节点 def buildTree(nodes): if not nodes: # 如果节点列表为空,则返回None return None root = TreeNode(nodes[0]) # 创建根节点,节点值为第一个元素 queue = [root] # 使用队列辅助进行层次遍历 index = 1 # 节点列表的索引 while queue: # 队列不为空时循环 node = queue.pop(0) # 弹出队列中的节点 if index < len(nodes): # 如果还有节点需要添加 if nodes[index] is not None: # 如果节点值不为None,创建左子节点 node.left = TreeNode(nodes[index]) queue.append(node.left) # 将左子节点放入队列 index += 1 # 索引加一 if index < len(nodes): # 如果还有节点需要添加 if nodes[index] is not None: # 如果节点值不为None,创建右子节点 node.right = TreeNode(nodes[index]) queue.append(node.right) # 将右子节点放入队列 index += 1 # 索引加一 return root # 返回根节点 def preorderTraversal(root): # 前序遍历二叉树(根-左-右) if root: print(root.val) # 打印当前节点的值 preorderTraversal(root.left) # 递归遍历左子树 preorderTraversal(root.right) # 递归遍历右子树 ``` 使用这个模板,你可以通过传入一个节点列表来构建一个二叉树,并使用`preorderTraversal`函数进行前序遍历,以打印二叉树中节点的值。 ### 回答3: 下面是一个用Python写的二叉树模板,其中有详细的中文注释: ```python class Node: def __init__(self, value): self.value = value self.left = None self.right = None class BinaryTree: def __init__(self): self.root = None def insert(self, value): """向二叉树中插入一个节点""" if self.root is None: self.root = Node(value) else: self._insert_recursive(value, self.root) def _insert_recursive(self, value, node): """递归插入节点的辅助函数""" if value < node.value: if node.left is None: node.left = Node(value) else: self._insert_recursive(value, node.left) else: if node.right is None: node.right = Node(value) else: self._insert_recursive(value, node.right) def search(self, value): """搜索二叉树中是否存在某个值""" return self._search_recursive(value, self.root) def _search_recursive(self, value, node): """递归搜索值的辅助函数""" if node is None or node.value == value: return node is not None elif value < node.value: return self._search_recursive(value, node.left) else: return self._search_recursive(value, node.right) def delete(self, value): """从二叉树中删除某个值""" self.root = self._delete_recursive(value, self.root) def _delete_recursive(self, value, node): """递归删除值的辅助函数""" if node is None: return None elif value < node.value: node.left = self._delete_recursive(value, node.left) elif value > node.value: node.right = self._delete_recursive(value, node.right) else: if node.left is None and node.right is None: node = None elif node.left is None: node = node.right elif node.right is None: node = node.left else: min_node = self._find_min(node.right) node.value = min_node.value node.right = self._delete_recursive(min_node.value, node.right) return node def _find_min(self, node): """找到右子树中的最小节点""" current = node while current.left is not None: current = current.left return current def inorder_traversal(self): """中序遍历二叉树""" self._inorder_recursive(self.root) def _inorder_recursive(self, node): """递归中序遍历的辅助函数""" if node is not None: self._inorder_recursive(node.left) print(node.value) self._inorder_recursive(node.right) ``` 这个二叉树模板包括了节点的插入、搜索、删除和中序遍历等常用操作,可以作为构建和操作二叉树的基础模板进行使用。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值