文章目录

  • BST相关概念
  • BST如何添加节点
  • BST如何遍历
  • BST如何求最值
  • BST如何删除节点
  • BST如何查找节点
  • 如何验证一棵树是BST

本文内容将主要介绍二叉查找树的相关概念,与关于二叉查找树的重要操作,如添加节点、删除节点等。

BST相关概念

二叉查找树(Binary Search Tree),又被称为二叉搜索树。在二叉查找树中,根结点的值一定大于左节点的值,一定小于右节点的值,例如下图所示:

特点:

  1. 任意节点的左子树不空, 则左子树上所有节点的key均小于它的根节点的key
  2. 任意节点的右子树不空, 则右子树上所有节点的key均大于它的根节点的key
  3. 任意节点的左,右子树也分别为二叉查找树
  4. 没有key相等的节点
  5. 二叉查找树进行中序遍历,可以得到一个递增的有序序列

BST如何添加节点

主要思想:

  • 二叉树为空,直接插入即可
  • 二叉树不为空,则比较即将被插入的节点与根节点的大小,如果比其大,则插入右子树中,否则插入左子树中,直至找到插入位置(新插入的结点一定是一个叶子结点)

原始树为一棵空树,执行操作如图:

  1. 插入值为15的节点,如下:

  2. 插入值为4的新节点

  3. 插入值20为的节点

  4. 插入值为17的节点


基本思想如上,我们给出实现代码如下:

    Node* Add(Node* node, int val){if(node == nullptr){return new Node(val);}if(val < node->val){node->left = Add(node->left, val);}else{node->right = Add(node->right, val);}return node;}

BST如何遍历

BST在本质上还是一棵二叉树,我们可以使用遍历二叉树的方式来进行遍历,如若对二叉树的遍历不是很理解,可以查看这篇博客:
数据结构】二叉树的深度优先遍历DFS和广度优先遍历BFS(含C++递归和非递归方式实现)

我们直接各给出遍历BST的代码,具体如下:

    void Print(Node* node)const{if(node == nullptr) return;if(node->left!=nullptr){cout << node->val << "->" << node->left->val << endl;Print(node->left);}if(node->right!=nullptr){cout << node->val << "->" << node->right->val << endl;Print(node->right);}}

BST如何求最值

因为BST的前序是一个有序树,这个特点就决定BST的最值位置是很特殊的,它的最大值位于树的最右下的节点,最小值位于最左下的节点,具体代码实现如下:

最大值:

    Node* Max(Node* node)const{if(nullptr == node) return nullptr;Node* p = node;while(nullptr != p->right){p = p->right;}return p;}

最小值:

    Node* Min(Node* node)const{if(nullptr == node) return nullptr;Node* p = node;while(nullptr != p->left){p = p->left;}return p;}

BST如何删除节点

BST结点的删除相较于我们刚了解的增添节点和遍历相对而言比较复杂,它不像二叉树删除结点的操作,直接将某一个叶子节点进行置换即可,在BST中,我们在删除某一个指定的节点后,还需要将该树整理为一个BST,即是让它的中序遍历有序递增。

具体思路如下:

删除节点是叶子节点:直接进行删除即可,删除之后该仍然是一棵BST;

删除节点的右/左子树为空,此时直接将该结点所有的右/左子树的根结点作为删除节点;

删除元素左右子树均不为空,我们在这里使用找到一个节点代替待删除节点即可。

  1. 这个节点其是最好是待删除节点的右子树的最小值(右子树最左下的节点),或者是左子树的最大值(左子树最右下的节点);
  2. 这样找的好处是找到的节点一定是一个叶子节点或者是一个左子树或者右子树为空的节点,我们就将删除一个左右子树为空的元素转化为删除一个要么左子树为空要么右子树为空(甚至为叶子结点)的元素。

具体思想大家理解了之后,我们给出实现代码如下:

    Node* Del(Node* node, int val){if(nullptr == root) return nullptr;if(node->val == val){if(nullptr==node->right && nullptr==node->left){// 叶子节点delete node;return nullptr;}if(nullptr == node->right){// 右子树为空// 直接使用当前待删除节点的左节点代替该结点Node* p = node->left;delete node;return p;}if(nullptr == node->left){// 左子树为空// 直接使用当前待删除节点的右节点代替该结点Node* p = node->right;delete node;return p;}// 左右孩子都有时// 直接使用该节点为根结点的右子树的最小值代替当前节点Node* maxNode =  Min(node->right);node->val = maxNode->val;node->right = Del(node->right, maxNode->val);}else if(node->val > val){node->left == Del(node->left, val);}else{node->right == Del(node->right, val);}return node;}

BST如何查找节点

我们知道BST的中序遍历结果是一个有序递增的数列,所以在BST中进行查找的操作的效率很高,该操作的计算复杂度与该树的高度成线性相关。

其实在本质上就是进行二分查找,当查找的节点值比当前节点值小,则比较当前节点的左子树的根结点(也就是左孩子),否则比较右子树的根结点(也就是右孩子),直至找到该节点,具体代码如下:

    Node* Search(Node* node, int val)const{if(nullptr == node) return nullptr;if(node->val == val) return node;if(node->val > val){return Search(node->left, val);}else{return Search(node->right, val);}}

如何验证一棵树是BST

这里有一个易错的点,因为BST的有序性,我们很容易想到利用比较树中的任意一个结点和其左右孩子的大小是否符合要求来判断,但这种判断方式是有问题的,例如这样一棵树:

这棵树中的任意一个结点的左孩子都小于其父节点,右孩子都大于父节点,但是这并不是一棵BST,值为5的节点应该位于值为15的左子树上。

判断一棵树是否是BST,应该比较树中的任意一个节点的左子树中的最大值比该结点小,右子树的最小值比其大。

具体代码如下:

    int maxleft(TreeNode* root){TreeNode* node = root;while(node->right!=nullptr){node = node->right;}return node->val;}int minright(TreeNode* root){TreeNode* node = root;while(node->left!=nullptr){node = node->left;}return node->val;}bool isValidBST(TreeNode* root){if(root == nullptr) return true;if(root->left!=nullptr && root->right!=nullptr){ //左右孩子均在if(root->val>=minright(root->right) || root->val<=maxleft(root->left)){return false;}else{return isValidBST(root->left) && isValidBST(root->right);}}else if(root->left!=nullptr){        // 左孩子在if(root->val<=maxleft(root->left)) return false;else{return isValidBST(root->left);}}else if(root->right!=nullptr){       // 右孩子在if(root->val>=minright(root->right)){return false;}else{return isValidBST(root->right);}} else{                                // 叶子节点return true;}return false;}

以上的代码虽然看起来很长,但是思路很清晰,大家应该很容易看懂,除此以外,我们给出一种简洁的代码解决这个问题,具体如下:

    bool isValidBST(TreeNode* root, long maxVal, long minVal){if(nullptr == root) return true;if(root->val <= minVal || root->val >=maxVal){return false;}return isValidBST(root->right, maxVal, root->val) && isValidBST(root->left, root->val, minVal);}bool isValidBST(TreeNode* root){return isValidBST(root, LONG_MAX, LONG_MIN);}

除此以外,我们还可以使用中序遍历该树,判断遍历结果是否有序,具体代码如下:

    double prevalue = -2147483649;  // prevalue将用于保存中序遍历过程中当前节点的前一个结点的值bool isValidBST(TreeNode* root) {if(root == NULL)  return true;if(!isValidBST(root->left)){return false;}if(prevalue >= root->val) {return false;}else{prevalue = root->val;}if(!isValidBST(root->right)){return false;}else{return true;}}

【数据结构】二叉查找树/二叉搜索树BST(附相关C++代码)相关推荐

  1. 二叉搜索树(BST的理论剖析+代码实现)

    二叉搜索树(BST树) 文章目录 二叉搜索树(BST树) 1.二叉搜索树的概念 2.二叉搜索树的结构定义 2.1 二叉搜索树结点模板的定义 2.2 二叉搜索树类模板的定义 3.二叉搜索树的效率 4.二 ...

  2. 二叉搜索树(BST)详解

    数据结构:二叉搜索树(BST) 今天咱们来聊聊二叉搜索树,先从字面上来理解,二叉,指的是有两个分支,左子树和右子树:搜索树,啥意思呢,搜索,是不是就是之前学过dfs和bfs那边学过,对啊,dfs就是深 ...

  3. 数据结构之二叉搜索树(BST)

    数据结构之二叉搜索树(BST) 1. 二叉搜索树定义 二叉搜索树(Binary Search Tree),又名二叉排序树(Binary Sort Tree). 二叉搜索树是具有有以下性质的二叉树: ( ...

  4. 【数据结构】二叉搜索树(BST树)的定义、构建、插入、删除及查找操作

    一.概念 二叉搜索树(BST树):又叫二叉排序树,二叉查找树.它或者是一棵空树:或者是具有以下性质的二叉树:     1.每个结点都有一个数据域,且所有节点的数据域互不相同:     2.若它的左子树 ...

  5. 【数据结构与算法】3.二叉搜索树(BST)、c++代码

    二叉搜索树(BST).c++代码 参考 https://blog.csdn.net/c_living/article/details/81021510

  6. 二叉搜索树BST的学习

    文章目录 二叉搜索树BST 什么是BST? 用BST做什么? 一.BST的特性 BST的特性是什么? 1.[230. 二叉搜索树中第K小的元素](https://leetcode.cn/problem ...

  7. 看动画学算法之:二叉搜索树BST

    文章目录 简介 BST的基本性质 BST的构建 BST的搜索 BST的插入 BST的删除 看动画学算法之:二叉搜索树BST 简介 树是类似于链表的数据结构,和链表的线性结构不同的是,树是具有层次结构的 ...

  8. 阿里开发者招聘节 | 面试题02-04:给定一个二叉搜索树(BST),找到树中第K小的节点

    为帮助开发者们提升面试技能.有机会入职阿里,云栖社区特别制作了这个专辑--阿里巴巴资深技术专家们结合多年的工作.面试经验总结提炼而成的面试真题这一次将陆续放出(面试题官方参考答案将在专辑结束后统一汇总 ...

  9. 二叉搜索树 (BST)

    二叉搜索树 (BST : Binary Search Tree) 又名 二叉查找树 或 二叉排序树. 二叉搜索树: 左孩子的值 一定小于或等于 父结点的值 二叉搜索树: 右孩子的值 一定大于或等于 父 ...

最新文章

  1. CVPR 2020 夜间目标检测挑战赛冠军方案解读
  2. 【学无止境】ajax长循环,反向ajax初体会,不用ws实现即时聊天
  3. java数据库驱动_Java数据库驱动链接大全
  4. [转载] Java8 Stream流遍历 如何使用索引
  5. BZOJ3172 TJOI2013 单词 AC自动机
  6. 大数据量下高并发同步
  7. python参考手册下载_python参考手册第4版
  8. 如何速成java_极*Java速成教程 - (4)
  9. 职称计算机 frontpage 2003,计算机职称考试FrontPage2003考试大纲
  10. 计算机导论应该学什么,《计算机导论A》教学大纲(计算机类)
  11. arcgis拼接影像
  12. 我的日程安排表 II
  13. 小程序项目之猫眼案例-代码
  14. PCA与2DPCA及2D-2DPCA零基础理解(上)
  15. SSM 框架原理简介及解析
  16. Matlab的GUI程序转换为单独可执行的exe文件
  17. 百度信息流是什么?哪些行业适合投放百度信息流?
  18. 软文标题怎么写?这8种标题写法你用对了吗
  19. 开源免费的WEB应用防火墙
  20. OpenJudge NOI 1.13 18:Tomorrow never knows?

热门文章

  1. java/android 设计模式学习笔记(1)---单例模式
  2. 如何修改Exchange邮箱的英文界面
  3. 炉石传说显示无法连接服务器失败,《炉石传说》无法连接到战网解决方法 无法连接请检查网络连接如何快速解决...
  4. 2007年8月28日 月全食
  5. 人工智能与人类智慧的较量
  6. IT、CT、UI、前端工程师以及后端工程师的简绍
  7. Android 简单的3D动画效果
  8. 喵呜:【Linux权限】
  9. 网络安全kali之利用宏感染word文档获取shell
  10. 双色球python最简单的写法,python编写一个双色球