难度参考
难度:中等
分类:二叉树
难度与分类由我所参与的培训课程提供,但需要注意的是,难度与分类仅供参考。且所在课程未提供测试平台,故实现代码主要为自行测试的那种,以下内容均为个人笔记,旨在督促自己认真学习。
题目
给定二叉搜索树(BST)的根节点和一个值。你需要在BST中找到节点值等于给定值的节点。返回以该节点为根的子树。如果节点不存在,则返回NULL.
示例1:
输入:root=[4,2,7,1,3],val=2
输出:[2,1,3]
示例2:
输入:root=[4,2,7,1,3],val=5
输出:[]
提示:
树中节点数在[1,5000]范围内
1<=Node.Va1<=10(7)
root是二叉搜索树
1<=val<=10(7)
额外:
希望你可以尝试使用迭代法,尤其要考虑二叉搜索树的特性,来优化迭代。
思路
这个问题要求在一个二叉搜索树中查找一个特定值的节点,并且返回以这个节点为根的子树。如果找不到这个值,则返回NULL。由于这是一个二叉搜索树,我们可以利用其特性来指导搜索过程,使之比一般的二叉树更高效。在二叉搜索树中,对于任何节点,其左子树中的所有节点都小于这个节点,而右子树中的所有节点都大于这个节点。
基于这个性质,我们可以使用如下思路来进行查找:
- 从树的根节点开始搜索。
- 比较当前节点的值与目标值:
- 如果当前节点的值等于目标值,那么我们找到了目标节点,返回这个节点即可。
- 如果目标值小于当前节点的值,那么我们应该在左子树中继续搜索。
- 如果目标值大于当前节点的值,那么我们应该在右子树中继续搜索。
- 如果当前节点是NULL,表示我们已经到达了叶子节点但未找到目标值,此时应该返回NULL。
- 重复以上步骤直到找到目标值或遍历到了叶子节点。
示例
假设我们有如下的二叉搜索树结构:
4
/ \
2 7
/ \
1 3
现在让我们分两个示例来查找值为2的节点。
示例一:查找值为2的节点
- 我们从根节点开始,也就是值为4的节点。
- 因为2小于4,我们向左子树移动。
- 现在我们在值为2的节点。我们比较当前节点的值(2)与目标值(2),发现它们相等。
- 我们找到了目标节点,并返回这个节点。
函数返回包含值为2的子树的根,也就是:
2
/ \
1 3
示例二:查找值为5的节点
- 我们从根节点开始,也就是值为4的节点。
- 因为5大于4,我们向右子树移动。
- 现在我们在值为7的节点。因为5小于7,我们向左子树移动。
- 在值为7的节点处,并没有左子节点,所以我们到达了NULL。
- 我们没有找到目标节点,返回NULL。
梳理
这样的实现能够工作,因为它依赖于二叉搜索树(Binary Search Tree, BST)的基本性质。在二叉搜索树中,每个节点都满足以下条件:
- 节点的左子树中的每个节点的值都小于当前节点的值。
- 节点的右子树中的每个节点的值都大于当前节点的值。
- 左子树和右子树也分别是二叉搜索树。
这个性质允许我们使用二分查找的方法快速地在树中定位一个值是否存在。具体到 searchBST
函数中的实现:
- 开始查找:我们从根节点开始查找。
- 比较值 :我们将目标值与当前节点的值进行比较。
- 如果目标值与当前节点的值相等,我们就找到了需要的节点,返回它;
- 如果目标值小于当前节点的值,根据二叉搜索树的性质,我们知道目标值(如果存在于树中)必定在当前节点的左子树中。因此,我们更新当前节点为其左子节点,继续查找;
- 如果目标值大于当前节点的值,那么目标值(同样如果存在)一定在当前节点的右子树中。因此,我们更新当前节点为其右子节点,继续查找。
- 终止条件 :这个过程会一直进行,直到当前节点为空(这意味着目标值不存在于树中,返回
nullptr
)或者找到了一个节点的值等于目标值(返回该节点)。
代码
#include <iostream> // 包含标准输入输出流的库
using namespace std; // 使用命名空间std,省去std::前缀
struct TreeNode { // 定义二叉树节点结构
int val; // 节点存储的值
TreeNode *left; // 指向左子树的指针
TreeNode *right; // 指向右子树的指针
TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} // 初始化构造函数,nullptr表示空指针
};
TreeNode* searchBST(TreeNode* root, int val) { // 定义搜索二叉搜索树的函数
while (root != nullptr && root->val != val) { // 当树不为空且当前节点值不等于目标值时
root = val < root->val ? root->left : root->right; // 判断目标值是在左子树还是右子树
}
return root; // 返回找到的节点指针,如果没找到则是nullptr
}
int main() { // 主函数
TreeNode* root = new TreeNode(4); // 创建根节点,赋值为4
root->left = new TreeNode(2); // 创建根的左子节点,赋值为2
root->right = new TreeNode(7); // 创建根的右子节点,赋值为7
root->left->left = new TreeNode(1); // 创建左子节点的左子节点,赋值为1
root->left->right = new TreeNode(3); // 创建左子节点的右子节点,赋值为3
int search_val = 2; // 设置要查找的值为2
TreeNode* result = searchBST(root, search_val); // 调用搜索函数
if (result != nullptr) { // 如果搜索结果不为空
cout << "搜索到节点值为 " << search_val << " 的节点是:" << result->val << endl;
if (result->left != nullptr) // 如果搜索到的节点的左子树不为空
cout << "左子节点:" << result->left->val << endl; // 打印左子节点的值
if (result->right != nullptr) // 如果搜索到的节点的右子树不为空
cout << "右子节点:" << result->right->val << endl; // 打印右子节点的值
} else { // 如果搜索结果为空
cout << "未找到节点值为 " << search_val << " 的节点" << endl; // 表明没找到节点
}
search_val = 5; // 设置要查找的值为5
result = searchBST(root, search_val); // 再次调用搜索函数
if (result != nullptr) { // 如果搜索结果不为空
cout << "搜索到节点值为 " << search_val << " 的节点是:" << result->val << endl;
if (result->left != nullptr) // 如果搜索到的节点的左子树不为空
cout << "左子节点:" << result->left->val << endl;
if (result->right != nullptr) // 如果搜索到的节点的右子树不为空
cout << "右子节点:" << result->right->val << endl;
} else { // 如果搜索结果为空
cout << "未找到节点值为 " << search_val << " 的节点" << endl; // 表明没找到节点
}
// 释放动态分配的内存(没写,懒)
return 0; // 主函数结束,返回0
}
时间复杂度:O(n)
空间复杂度:O(n)