热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

(转)查找算法:二叉排序树(BSTree)

二叉排序树(BinarySortTree),又称为二叉查找树(BinarySearchTree),即BSTree。构造一棵二叉排序树的目的,

二叉排序树(Binary Sort Tree),又称为二叉查找树(Binary Search Tree) ,即BSTree。

构造一棵二叉排序树的目的,其实并不是为了排序,而是为了提高查找和插入删除的效率。

什么是二叉排序树呢?二叉排序树具有以下几个特点。

(1)若根节点有左子树,则左子树的所有节点都比根节点小。

(2)若根节点有右子树,则右子树的所有节点都比根节点大。

(3)根节点的左,右子树也分别是二叉排序树。

1、二叉排序树的图示

下面是二叉排序树的图示,通过它可以加深对二叉排序树的理解。

 

2、二叉排序树常见的操作及思路

下面是二叉排序树常见的操作及思路。

2-1、插入节点

思路:比如我们要插入数字20到这棵二叉排序树中。那么步骤如下:

(1)首先将20与根节点进行比较,发现比根节点小,所以继续与根节点的左子树30比较。

(2)发现20比30也要小,所以继续与30的左子树10进行比较。

(3)发现20比10要大,所以就将20插入到10的右子树中。

此时的二叉排序树如下图:

 

2-2、查找节点

比如我们要查找节点10,那么思路如下:

(1)还是一样,首先将10与根节点50进行比较,发现比根节点要小,所以继续与根节点的左子树30进行比较。

(2)发现10比左子树30要小,所以继续与30的左子树10进行比较。

(3)发现两值相等,即查找成功,返回10的位置。

 

2-3、删除节点

删除节点的情况相对复杂,主要分为以下三种情形:

(1)删除的是叶节点(即没有孩子节点的)。比如20,删除它不会破坏原来树的结构,最简单。如图所示。

 

(2)删除的是单孩子节点。比如90,删除它后需要将它的孩子节点与自己的父节点相连。情形比第一种复杂一些。

 

(3)删除的是有左右孩子的节点。比如根节点50

这里有一个问题就是删除它后,谁将作为根节点?利用二叉树的中序遍历,就是右节点的左子树的最左孩子

 

3、代码

有了思路之后,下面就开始写代码来实现这些功能。

BSTreeNode.java

public class BSTreeNode {public int data; public BSTreeNode left; public BSTreeNode right; public BSTreeNode(int data) { this.data = data; } }

 

BSTreeOperate.java

/*** 二叉排序树的常见操作*/
public class BSTreeOperate { // 树的根节点 public BSTreeNode root; // 记录树的节点个数 public int size; /** * 创建二叉排序树 * * &#64;param list * &#64;return */ public BSTreeNode create(int[] list) { for (int i &#61; 0; i ) { insert(list[i]); } return root; } /** * 插入一个值为data的节点 * * &#64;param data */ public void insert(int data) { insert(new BSTreeNode(data)); } /** * 插入一个节点 * * &#64;param bsTreeNode */ public void insert(BSTreeNode bsTreeNode) { if (root &#61;&#61; null) { root &#61; bsTreeNode; size&#43;&#43;; return; } BSTreeNode current &#61; root; while (true) { if (bsTreeNode.data <&#61; current.data) { // 如果插入节点的值小于当前节点的值&#xff0c;说明应该插入到当前节点左子树&#xff0c;而此时如果左子树为空&#xff0c;就直接设置当前节点的左子树为插入节点。 if (current.left &#61;&#61; null) { current.left &#61; bsTreeNode; size&#43;&#43;; return; } current &#61; current.left; } else { // 如果插入节点的值大于当前节点的值&#xff0c;说明应该插入到当前节点右子树&#xff0c;而此时如果右子树为空&#xff0c;就直接设置当前节点的右子树为插入节点。 if (current.right &#61;&#61; null) { current.right &#61; bsTreeNode; size&#43;&#43;; return; } current &#61; current.right; } } } /** * 中序遍历 * * &#64;param bsTreeNode */ public void LDR(BSTreeNode bsTreeNode) { if (bsTreeNode !&#61; null) { // 遍历左子树 LDR(bsTreeNode.left); // 输出节点数据 System.out.print(bsTreeNode.data &#43; " "); // 遍历右子树 LDR(bsTreeNode.right); } } /** * 查找节点 */ public boolean search(BSTreeNode bsTreeNode, int key) { // 遍历完没有找到&#xff0c;查找失败 if (bsTreeNode &#61;&#61; null) { return false; } // 要查找的元素为当前节点&#xff0c;查找成功 if (key &#61;&#61; bsTreeNode.data) { return true; } // 继续去当前节点的左子树中查找&#xff0c;否则去当前节点的右子树中查找 if (key < bsTreeNode.data) { return search(bsTreeNode.left, key); } else { return search(bsTreeNode.right, key); } } }

 

BSTreeOperateTest.java

public class BSTreeOperateTest {public static void main(String[] args) { BSTreeOperate bsTreeOperate &#61; new BSTreeOperate(); int[] list &#61; new int[]{50, 30, 70, 10, 40, 90, 80}; System.out.println("*********创建二叉排序树*********"); BSTreeNode bsTreeNode &#61; bsTreeOperate.create(list); System.out.println("中序遍历原始的数据&#xff1a;"); bsTreeOperate.LDR(bsTreeNode); System.out.println(""); System.out.println(""); System.out.println("********查找节点*******"); System.out.println("元素20是否在树中&#xff1a;" &#43; bsTreeOperate.search(bsTreeNode, 20)); System.out.println(""); System.out.println("********插入节点*******"); System.out.println("将元素20插入到树中"); bsTreeOperate.insert(20); System.out.println("中序遍历&#xff1a;"); bsTreeOperate.LDR(bsTreeNode); System.out.println(""); System.out.println(""); System.out.println("********查找节点*******"); System.out.println("元素20是否在树中&#xff1a;" &#43; bsTreeOperate.search(bsTreeNode, 20)); System.out.println(""); } }

 

运行结果&#xff1a;

 

 

欢迎转载&#xff0c;但请保留文章原始出处

本文地址&#xff1a;http://www.cnblogs.com/nnngu/p/8294714.html

转:https://www.cnblogs.com/schips/p/10901518.html



推荐阅读
  • 本文介绍了Java并发库中的阻塞队列(BlockingQueue)及其典型应用场景。通过具体实例,展示了如何利用LinkedBlockingQueue实现线程间高效、安全的数据传递,并结合线程池和原子类优化性能。 ... [详细]
  • 优化ListView性能
    本文深入探讨了如何通过多种技术手段优化ListView的性能,包括视图复用、ViewHolder模式、分批加载数据、图片优化及内存管理等。这些方法能够显著提升应用的响应速度和用户体验。 ... [详细]
  • 1:有如下一段程序:packagea.b.c;publicclassTest{privatestaticinti0;publicintgetNext(){return ... [详细]
  • 本文介绍如何在 Android 中通过代码模拟用户的点击和滑动操作,包括参数说明、事件生成及处理逻辑。详细解析了视图(View)对象、坐标偏移量以及不同类型的滑动方式。 ... [详细]
  • 深入解析Android自定义View面试题
    本文探讨了Android Launcher开发中自定义View的重要性,并通过一道经典的面试题,帮助开发者更好地理解自定义View的实现细节。文章不仅涵盖了基础知识,还提供了实际操作建议。 ... [详细]
  • 本文详细介绍了Java中org.neo4j.helpers.collection.Iterators.single()方法的功能、使用场景及代码示例,帮助开发者更好地理解和应用该方法。 ... [详细]
  • 本文将介绍如何编写一些有趣的VBScript脚本,这些脚本可以在朋友之间进行无害的恶作剧。通过简单的代码示例,帮助您了解VBScript的基本语法和功能。 ... [详细]
  • Explore a common issue encountered when implementing an OAuth 1.0a API, specifically the inability to encode null objects and how to resolve it. ... [详细]
  • C++实现经典排序算法
    本文详细介绍了七种经典的排序算法及其性能分析。每种算法的平均、最坏和最好情况的时间复杂度、辅助空间需求以及稳定性都被列出,帮助读者全面了解这些排序方法的特点。 ... [详细]
  • 主要用了2个类来实现的,话不多说,直接看运行结果,然后在奉上源代码1.Index.javaimportjava.awt.Color;im ... [详细]
  • 本文详细介绍了 Dockerfile 的编写方法及其在网络配置中的应用,涵盖基础指令、镜像构建与发布流程,并深入探讨了 Docker 的默认网络、容器互联及自定义网络的实现。 ... [详细]
  • 本文详细介绍了Java中org.eclipse.ui.forms.widgets.ExpandableComposite类的addExpansionListener()方法,并提供了多个实际代码示例,帮助开发者更好地理解和使用该方法。这些示例来源于多个知名开源项目,具有很高的参考价值。 ... [详细]
  • 使用 Azure Service Principal 和 Microsoft Graph API 获取 AAD 用户列表
    本文介绍了一段通用代码示例,该代码不仅能够操作 Azure Active Directory (AAD),还可以通过 Azure Service Principal 的授权访问和管理 Azure 订阅资源。Azure 的架构可以分为两个层级:AAD 和 Subscription。 ... [详细]
  • 深入解析Spring Cloud Ribbon负载均衡机制
    本文详细介绍了Spring Cloud中的Ribbon组件如何实现服务调用的负载均衡。通过分析其工作原理、源码结构及配置方式,帮助读者理解Ribbon在分布式系统中的重要作用。 ... [详细]
  • 本文详细介绍了Akka中的BackoffSupervisor机制,探讨其在处理持久化失败和Actor重启时的应用。通过具体示例,展示了如何配置和使用BackoffSupervisor以实现更细粒度的异常处理。 ... [详细]
author-avatar
用户geafr1kx8g
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有