1. 先序二叉树的概念
二叉树是一种非常重要的数据结构,它可以用来解决很多实际问题,比如搜索、排序等。在二叉树中,每个结点最多只有两个子结点,我们把它们分为左子树和右子树。
先序二叉树是一种遍历方式,也叫先序遍历。对于一棵二叉树,先序遍历的顺序是:先访问根节点,然后遍历左子树,最后遍历右子树。
对于如下二叉树:
1
/ \
2 3
/ \ / \
4 5 6 7
它的先序遍历结果是:1 2 4 5 3 6 7。
2. 先序二叉树构建的方法
2.1 普通版先序二叉树构建
构建先序二叉树,我们需要先将根节点插入到二叉树中,然后将左子树和右子树递归插入。
以下是先序二叉树构建的代码:
// 二叉树结点的定义
struct TreeNode {
int val;
TreeNode* left;
TreeNode* right;
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
// 递归终止条件:先序遍历序列为空,返回 nullptr
if (preorder.empty()) {
return nullptr;
}
// 新建一个结点,作为根节点
TreeNode* root = new TreeNode(preorder[0]);
// 找到根节点在中序遍历序列中的位置
auto idx = find(inorder.begin(), inorder.end(), preorder[0]) - inorder.begin();
// 将中序遍历序列分成左子树和右子树两个部分
vector<int> left_inorder(inorder.begin(), inorder.begin() + idx);
vector<int> right_inorder(inorder.begin() + idx + 1, inorder.end());
// 将先序遍历序列分成左子树和右子树两个部分
vector<int> left_preorder(preorder.begin() + 1, preorder.begin() + 1 + idx);
vector<int> right_preorder(preorder.begin() + 1 + idx, preorder.end());
// 递归构建左子树和右子树
root->left = buildTree(left_preorder, left_inorder);
root->right = buildTree(right_preorder, right_inorder);
return root;
}
};
这里的思路就是递归实现,每次取先序遍历序列的第一个元素作为根节点,然后在中序遍历序列中找到该节点的位置。
再根据该位置,将中序遍历序列分成左子树和右子树两个部分,同时也要将先序遍历序列分成左子树和右子树两个部分。然后递归构建左子树和右子树。
2.2 细节处理版先序二叉树构建
以上代码是普通版的解决方案,但是在实际使用中,会遇到一些问题。比如可能会有重复元素。如果使用以上算法进行构建,会出现多次插入同样的元素,从而导致程序出错。为了避免这种情况的发生,我们需要对代码进行一些细节处理。
以下是细节处理版的先序二叉树构建代码:
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
// 使用哈希表记录中序遍历中每个元素的位置
unordered_map<int,int> pos;
for (int i = 0; i < inorder.size(); ++i) {
pos[inorder[i]] = i;
}
// 递归构建二叉树
return build(preorder, inorder, 0, preorder.size() - 1, 0, inorder.size() - 1, pos);
}
/**
* 递归构建二叉树
*/
TreeNode* build(vector<int>& preorder, vector<int>& inorder, int pl, int pr, int il, int ir, unordered_map<int, int>& pos) {
if (pl > pr) {
return nullptr;
}
int k = pos[preorder[pl]];
int cnt = k - il;
TreeNode* root = new TreeNode(preorder[pl]);
root->left = build(preorder, inorder, pl + 1, pl + cnt, il, k - 1, pos);
root->right = build(preorder, inorder, pl + cnt + 1, pr, k + 1, ir, pos);
return root;
}
};
这里我们使用哈希表记录中序遍历中每个元素的位置,避免重复添加同样的元素。
另外,在递归构建二叉树的过程中,我们传递的是左右子树的起止位置,也更符合实际递归的过程。
3. 总结
先序二叉树构建是一道经典的题目,在算法面试中经常出现。掌握这种算法是程序员必备的技能之一。本文介绍了两种构建先序二叉树的方法,普通版和细节处理版,我们需要根据具体的问题和题目来选择适合的解决方案。
此外,在代码实现中要注意细节处理,比如元素重复、数组越界等。
希望本文能够对大家掌握先序二叉树构建有所帮助。