二叉搜索树(Binary Search Tree),简称BST,顾名思义,一颗可以用于搜索的二叉树。BST在数据结构中占有很重要的地位,一些高级树结构都是其的变种,例如AVL树、红黑树等,因此理解BST对于后续树结构的学习有很好的作用。同时利用BST可以进行排序,称为二叉排序,也是很重要的一种思想。

  二叉树的性质:任意一个节点的所有左子树元素都比该元素值要小,而所有右子树元素都比该元素值要大。

  符合该性质的二叉树就是一颗二叉搜索树,当然前提下是树中不允许有重复元素。

  所有的二叉搜索树的中序遍历序列都是一个顺序序列, 以下的几种都是二叉搜索树

  

  接下来讲二叉搜索树的三个主要操作:查找,增加,删除。

  一、查找

    二叉搜索树本来就是用于查找数据的一种结构,主要步骤是:

      ① 选择根节点作为当前节点

      ② 如果当前节点为null,则返回false表示找不到该元素

      ③ 如果当前节点不为null,判断当前节点是否与所搜索元素相等,如相等,则返回true表示能找到该元素

      ④ 如果当前节点的值比所搜索值小,则选择当前节点的左节点作为当前节点,比搜索值大则选择右节点作为当前节点,然后从②循环过程

  二、增加

    二叉搜索树增加节点重点是根据查找元素的过程找到该节点的插入位置:

      ① 如果根节点为空,则当前插入(增加)的节点为二叉树的根,如根节点不为空,设置根节点为当前节点

      ② 如果当前节点的值与插入节点的值相等,返回false表示插入失败,节点值已存在于树中

      ③ 若插入节点的值比当前节点的值小,且当前节点的左子树为空,则把插入节点增加到当前节点的左子树,并返回true表示插入成功,如左子树不为空,设置当前节点的左子树为当前节点。

        如果插入节点的值比当前节点的值大,且当前节点的右子树为空,则把插入节点增加到当前节点的右子树,并返回true,如右子树不为空,设置当前节点的右子树为当前节点。

        从②循环过程

    具体代码如下:

    public boolean insert(int elem) {TreeNode node = new TreeNode(elem);if (null == this.root) {this.root = node;return true;} else {return insertChild(this.root, node);}}    /*** insert the newNode to the child position of parent node* @param parent* @param newNode* @return true if the newNode insert successfully or false if the newNode have been exist*/private boolean insertChild(TreeNode parent, TreeNode newNode) {if (parent.getElem() == newNode.getElem()) {return false;} else if (parent.getElem() > newNode.getElem()) {if (null  == parent.getLeft()) {parent.setLeft(newNode);newNode.setParent(parent);return true;} else {return insertChild(parent.getLeft(), newNode);}} else {if (null == parent.getRight()) {parent.setRight(newNode);newNode.setParent(parent);return true;} else {return insertChild(parent.getRight(), newNode);}}}

  三、删除

    二叉搜索树的删除操作重点在于删除这个节点之后对其他节点的重组,根据删除节点位置又分为以下几种情况:

      情况1 删除节点为叶子节点:直接删除这个节点(把父节点对应的子树设为空)

      情况2 删除节点只有左子树或只有右子树:用左子树或者右子树代替被删除节点(把父节点对应的子树指向删除节点的左子树或者右子树,并把左子树或右子树的父节点指向删除节点的父节点)

      *情况3 删除节点的左子树和右子树均不为空:找到删除节点的直接前驱节点,用该前驱节点的值替换待删除节点的值,然后把这个前驱节点当做待删除节点,则该情况转换成情况1或者情况2

      比如想删除节点 4

    

     找到节点4的直接前驱节点3,用节点3的值代替节点4的值,然后情况换成删除节点3(也就是情况1)。

    具体代码:

    /*** delete the node which element equals to parameter elem* @param elem* @return true if the node can be found and delete otherwise false*/public boolean delete(int elem) {if (null == this.root) {return false;} else {TreeNode node = this.root;// find out the node need to be deletedwhile (null != node) {if (node.getElem() == elem) {deleteNode(node);return true;} else if (node.getElem() > elem) {node = node.getLeft();} else {node = node.getRight();}}return false;}}private void deleteNode(TreeNode node) {if (null == node.getLeft() && null == node.getRight()) {// deleted node is a leaveif (null  == node.getParent()) {// deleted node is rootthis.root = null;} else if (node == node.getParent().getLeft()) {// deleted node is the left child of its parentnode.getParent().setLeft(null);} else {// deleted node is the right child of its parentnode.getParent().setRight(null);}} else if (null == node.getLeft()) {// deleted node only hae right childif (null  == node.getParent()) {this.root = node.getRight();} else if (node == node.getParent().getLeft()) {node.getParent().setLeft(node.getRight());} else {node.getParent().setRight(node.getRight());}node.getRight().setParent(node.getParent());} else if (null == node.getRight()) {// deleted node only have left childif (null  == node.getParent()) {this.root = node.getLeft();} else if (node == node.getParent().getLeft()) {node.getParent().setLeft(node.getLeft());} else {node.getParent().setRight(node.getLeft());}node.getLeft().setParent(node.getParent());} else {// deleted node have both left & right children// find out the precursor of deleted node// the precursor node replace the position of deleted nodeTreeNode pre = node.getLeft();while (null != pre.getRight()) {pre  = pre.getRight();}// swap the elem of precursor node and deleted node// then delete the precursor node
            TreeUtils.swapTreeElem(pre, node);deleteNode(pre);}}

写个小程序测试一下:

输入测试数据:10 5 2 7 6 18 13 -1(-1是结束输入,不作为一个元素值)

1. insert
2. delete
3. search
4. print
5. exit
->1
->10 5 2 7 6 18 13 -1
insert success

看一下树的结构,显示树结构的需要顺时针转90°来看,并自己想象节点连线。。

1. insert
2. delete
3. search
4. print
5. exit
->4
-1813
107652
-

删除节点 5 测试效果

1. insert
2. delete
3. search
4. print
5. exit
->2
->5
delete success
--------------------------------------------------------------
1. insert
2. delete
3. search
4. print
5. exit
->4
-1813
10762
-

至此, 二叉搜索树的操作及具体实现完成,如有不妥之处,欢迎指出斧正。

尊重知识产权,转载请标明出处并通知作者。

转载于:https://www.cnblogs.com/GNLin0820/p/9120331.html

数据结构 - 从二叉搜索树说到AVL树(一)之二叉搜索树的操作与详解(Java)相关推荐

  1. 08_Python算法+数据结构笔记-二叉搜索树查询/删除-AVL树旋转/插入/应用-贪心算法

    b站视频:路飞IT学城 清华计算机博士带你学习Python算法+数据结构_哔哩哔哩_bilibili #71 二叉搜索树:查询 import randomclass BiTreeNode:def __ ...

  2. AVL树(平衡二叉搜索树)

    AVL树 一.AVL树 1.AVL树的概念 2.AVL树节点的定义(描述) 3.AVL树的插入 4.AVL树的旋转 (1)左单旋 (2)右单旋 (3)左右双旋 (4)右左双旋 (5)插入的整体代码 5 ...

  3. AVL树(平衡二叉搜索树)详解及C++代码实现

    AVL树简介 AVL树实际上一个引入了平衡因子的二叉搜索树,该平衡因子保证了每个节点的左右子树高度之差的绝对值不超过1,这样就可以降低树的高度,减少平均搜索长度. 一棵AVL树或者是空树,或者是具有以 ...

  4. 【大话数据结构C语言】57 平衡二叉树(AVL树)

    欢迎关注我的公众号是[CodeAllen],关注回复[1024]获取精品学习资源 程序员技术交流①群:736386324 ,程序员技术交流②群:371394777 平衡二叉排序树 平衡二叉树是一种二叉 ...

  5. ecshop二次开发 给商品添加自定义字段【包含我自己进一步的开发实例详解】

    本文包含商品自定义添加教程及进一步的开发实例: 教程: 说起自定义字段,我想很多的朋友像我一样会想起一些开源的CMS(比如Dedecms.Phpcms.帝国)等,他们是可以在后台直接添加自定义字段的. ...

  6. 算法:二叉搜索树BST - 删除节点 详解(Java实现)

    删除节点 删除节点存在 3 种情况,几乎所有类似博客都提到了这点.这 3 种情况分别如下: 没有左右子节点,可以直接删除 存在左节点或者右节点,删除后需要对子节点移动 同时存在左右子节点,不能简单的删 ...

  7. 有序数组二分查找java_详解Java数据结构和算法(有序数组和二分查找)

    一.概述 有序数组中常常用到二分查找,能提高查找的速度.今天,我们用顺序查找和二分查找实现数组的增删改查. 二.有序数组的优缺点 优点:查找速度比无序数组快多了 缺点:插入时要按排序方式把后面的数据进 ...

  8. 青源LIVE第29期|清华叉院高阳:使用1/500数据掌控Atari游戏-EfficientZero算法详解

    当前强化学习已在许多应用中取得了巨大成功.但样本效率仍是强化学习中一个重大挑战,重要的方法需要数百万(甚至数十亿)的环境步骤来训练.虽然,当前在基于图像的样本高效RL算法方面取得了重大进展:但是,在A ...

  9. 二、操作系统——用信号量机制实现进程互斥、同步、前驱关系(详解)

    一.什么是进程同步? 二.什么是进程互斥? 临界资源:一个时间段内只允许一个进程使用的资源 为了实现对临界资源的互斥访问,同时保证系统整体性能,需要遵循以下原则: 空闲让进.临界区空闲时,可以允许一个 ...

最新文章

  1. opencv-车牌区域提取
  2. sonarqube静态扫描代码环境搭建及使用(本地环境)
  3. CSS之定位布局(position,relative定位布局技巧)
  4. Linux系统编程41:多线程之线程池的概念及实现
  5. 不再是顶配专属iPhone 13系列将全系标配LiDAR激光雷达
  6. C++STL笔记(二):容器的特性和共通操作
  7. Spring中为什么实体类不用注入
  8. Jersey学习笔记
  9. idea 下查看项目代码量、行数
  10. 八部众---走出软件作坊:三五个人十来条枪 如何成为开发正规军(二十三)
  11. linux samba文件共享,网络凭据总是出错解决方法
  12. 【Shell编程】几个小案例
  13. 记 PS2020 打开闪退问题
  14. C#使用NPOI操作Word表格
  15. 微软小娜关闭服务器,请问微软小娜 (Cortana) 要退出中国了吗?
  16. 使用pandas对excel追加列数据
  17. java-php-python-ssm漠河旅游官网计算机毕业设计
  18. Millumin 3 for mac(专业视频编辑软件)
  19. JavaScript---constructor 和 prototype详解
  20. (导航页)OpenStack-M版-双节点手工搭建-附B站视频

热门文章

  1. 网络间谍又添利器:新型远程访问木马Trochilus
  2. “模板类与友元”那些事(C++)
  3. 使用Spring Session做分布式会话管理
  4. vsftp建立虚拟用户不同目录分配不同权限操作步骤详解
  5. 阅读《第31次中国互联网络发展状况统计报告》,分析中国互联网发展趋势和特点...
  6. library at girton
  7. 剑桥大学的组织架构和行政机构:学院高度自制
  8. 《守望先锋》阵亡镜头、全场最佳和亮眼表现是如何设计
  9. 【转】强大的B树B+树
  10. C++构造函数调用虚函数的后果