• 代码随想录 第八章 二叉树:二叉搜索树


    纸上得来终觉浅,觉知此事要躬行

    二叉搜索树的定义。

    若它的左子树不为空,则左子树上所有节点的值均小于它的根节点的值。

    若它的右字树不为空,则右子树上所有节点的值均大于它的根节点的值。

    它的左、右子树也分别为二叉搜索树。

    二叉搜索树是有序数,这就决定了二叉搜索树的递归遍历、迭代遍历和普通二叉树都不一样。

    15、在二叉搜索树中寻找节点

    leetcode700:

    确定一个节点是否存在二叉搜索树中,如果在,则返回这个节点,如果不在,则返回null。

    (1)、递归法

    因为二叉搜索树的节点是有序的,所以可以有方向地搜索。如果root->val大于val,则搜索左子树,如果root->val小于val,则搜索右子树,如果没有找到目标节点,则返回null。

    1. #include
    2. using namespace std;
    3. typedef struct _tag_BitNode {
    4. int data;
    5. _tag_BitNode* left;
    6. _tag_BitNode* right;
    7. _tag_BitNode(int val) {
    8. data = val;
    9. left = nullptr;
    10. right = nullptr;
    11. }
    12. }BitNode,*BitNodePtr;
    13. BitNode* SearchBST(BitNode* root, int val) {
    14. if (root == nullptr || root->data == val) {
    15. return root;
    16. }
    17. if (root->data > val) {
    18. return SearchBST(root->left, val);
    19. }
    20. if (root->data < val) {
    21. return SearchBST(root->right, val);
    22. }
    23. return nullptr;
    24. }
    25. void main() {
    26. BitNode node0(4), node1(2), node2(7);
    27. BitNode node3(1), node4(3), node5(6), node6(8);
    28. node0.left = &node1;
    29. node0.right = &node2;
    30. node1.left = &node3;
    31. node1.right = &node4;
    32. node2.left = &node5;
    33. node2.right = &node6;
    34. BitNode* ret = SearchBST(&node0, 3);
    35. cout << "hell world" << endl;
    36. }

    (2)、迭代法

    一提到二叉树遍历的迭代法,读者可能立刻想到使用栈模拟深度遍历,使用队列模拟广度遍历。但对于二叉搜索树就不一样了,基于二叉搜索树的特殊性,也就是节点的有序性,不适用辅助栈或者队列就可以写成迭代法。

    对于一般二叉树,递归过程中还有回溯的过程。例如,遍历一个左方向的分支到头了,就需要调头,再遍历右分支。而对于二叉搜索树,不需要回溯的过程,基于节点的有序性就可以确定搜索方向。

    1. BitNode* SearchBSTIter(BitNode* root,int val) {
    2. while (root != nullptr) {
    3. if (root->data > val) {
    4. root = root->left;
    5. }
    6. else if (root->data < val) {
    7. root = root->right;
    8. }
    9. else {
    10. return root;
    11. }
    12. }
    13. return nullptr;
    14. }

    本节介绍了二叉搜索树的遍历方式,基于二叉搜索树的特性,遍历的时候要比普票的二叉树简单得多,一些读者很容易忽略二叉搜索树的特性而写出很复杂的代码。所以针对二叉搜索树的题目,一定要利用其特性。

    16、验证二叉搜索树

    leetcode98:验证二叉搜索树

    判断二叉树是不是二叉搜索树的条件如下:

    (1)、若它的左子树不为空,则左子树上所有节点的值均小于它的根节点的值。

    (2)、若它的右子树不为空,则右子树上所有节点的值均大于它的根节点的值。

    (3)、它的左、右字树也分别为二叉搜索树。

    采用中序遍历时,输出的二叉树搜索树节点的数值是有序序列。基于这个特性,验证二叉搜索树就相当于判断一个序列是不是递增的。

    递归法:

    可以采用中序遍历将二叉搜索树转变成一个数组,只要比较这个数组是不是有序的即可,如果数组是有序的,则是二叉搜索树。

    1. class Solution {
    2. private:
    3. vector<int> vec;
    4. void Inorder(BitNode* root) {
    5. if (root == nullptr) {
    6. return ;
    7. }
    8. Inorder(root->left);
    9. vec.push_back(root->data);
    10. Inorder(root->right);
    11. }
    12. public:
    13. bool IsValidBST(BitNode* root) {
    14. vec.clear();
    15. Inorder(root);
    16. for (int i = 1; i < vec.size(); i++) {
    17. if (vec[i] < vec[i - 1]) {
    18. return false;
    19. }
    20. }
    21. return true;
    22. }
    23. };

    迭代法:

    1. bool IsValidBSF(BitNode* root) {
    2. stack st;
    3. BitNode* cur = root;
    4. BitNode* pre = nullptr;
    5. while (cur != nullptr || !st.empty()) {
    6. if (cur != nullptr) {
    7. st.push(cur);
    8. cur = cur->left;
    9. }
    10. else {
    11. cur = st.top();
    12. st.pop();
    13. if (pre != nullptr && cur->data <= pre->data) {
    14. return false;
    15. }
    16. pre = cur;
    17. cur = cur->right;
    18. }
    19. }
    20. return true;
    21. }

    17、二叉搜索树的最小绝对值

    leetcode530:二叉搜索树中的最小绝对值

    给出一颗树所有节点为非负值的二叉搜索树,请计算树中任意两个节点的差的绝对值的最小值。

    (1)、递归法

    注意是二叉搜索树,二叉搜素树是有序的。遇到二叉搜索树上求最值,求差值问题,就把它想象成在一个有序数组上求最值、求差值,这样就简单多了。

    1. class Solution {
    2. private:
    3. vector<int> vec;
    4. void TraverSal(BitNode* root) {
    5. if (root == nullptr) {
    6. return;
    7. }
    8. TraverSal(root->left);
    9. vec.push_back(root->data);
    10. TraverSal(root->right);
    11. }
    12. public:
    13. int GetMinimumDifference(BitNode* root) {
    14. vec.clear();
    15. TraverSal(root);
    16. if (vec.size() < 2) {
    17. return 0;
    18. }
    19. int result = INT_MAX;
    20. for (int i = 1; i < vec.size(); i++) {
    21. result = min(result, (vec[i] - vec[i - 1]));
    22. }
    23. return result;
    24. }
    25. };

    其实对二叉树进行中序遍历的过程中,我们可以直接找到相邻两个节点的差值:用一个pre节点记录cur节点的前一个节点。

    1. class Solution {
    2. private:
    3. int result = INT_MAX;
    4. BitNode* pre = nullptr;
    5. void TraverSal(BitNode* cur) {
    6. if (cur == nullptr) {
    7. return;
    8. }
    9. TraverSal(cur->left);
    10. if (pre != nullptr) {
    11. result = min(result, cur->data - pre->data);
    12. }
    13. pre = cur;
    14. TraverSal(cur->right);
    15. }
    16. public:
    17. int GetMinimumDifference(BitNode* root) {
    18. TraverSal(root);
    19. return result;
    20. }
    21. };

    迭代法:

    下面给出一种中序遍历的迭代法

    1. class Solution {
    2. public:
    3. int GetMinimumDifference(BitNode* root) {
    4. stack st;
    5. BitNode* cur = root;
    6. BitNode* pre = nullptr;
    7. int result = INT_MAX;
    8. while (cur != nullptr || !st.empty()) {
    9. if (cur != nullptr) {
    10. st.push(cur);
    11. cur = cur->left;
    12. }
    13. else {
    14. BitNode* node = st.top();
    15. st.pop();
    16. if (pre != nullptr) {
    17. result = min(result, cur->data - pre->data);
    18. }
    19. pre = cur;
    20. cur = cur->right;
    21. }
    22. }
    23. return result;
    24. }
    25. };

  • 相关阅读:
    MyBatis - 两种查询树形数据(最多三级结构)
    IVariantArray的注意事项:AE 调用GP工具方法介绍及常见错误“对 COM 组件的调用返回了错误 HRESULTE_FAIL
    探究大语言模型如何使用长上下文
    【愚公系列】2022年09月 MAUI框架-MAUI项目的创建
    【C语言】指针查漏补缺
    汽车FBL概述
    数据中台选型必读(四):要想中台建的好,数据模型得做好
    Vue3:创建脚手架
    eclipse导入maven项目
    设计一个高效算法,将顺序表L的所有元素逆置,要求算法的空间复杂度为O(1)
  • 原文地址:https://blog.csdn.net/qq_32565805/article/details/133514563