热门标签 | 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



推荐阅读
  • 本文探讨了如何在 F# Interactive (FSI) 中通过 AddPrinter 和 AddPrintTransformer 方法自定义类型(尤其是集合类型)的输出格式,提供了详细的指南和示例代码。 ... [详细]
  • 并发编程 12—— 任务取消与关闭 之 shutdownNow 的局限性
    Java并发编程实践目录并发编程01——ThreadLocal并发编程02——ConcurrentHashMap并发编程03——阻塞队列和生产者-消费者模式并发编程04——闭锁Co ... [详细]
  • 实用正则表达式有哪些
    小编给大家分享一下实用正则表达式有哪些,相信大部分人都还不怎么了解,因此分享这篇文章给大家参考一下,希望大家阅读完这篇文章后大有收获,下 ... [详细]
  • 本文介绍了如何使用JavaScript的Fetch API与Express服务器进行交互,涵盖了GET、POST、PUT和DELETE请求的实现,并展示了如何处理JSON响应。 ... [详细]
  • 深入解析Spring启动过程
    本文详细介绍了Spring框架的启动流程,帮助开发者理解其内部机制。通过具体示例和代码片段,解释了Bean定义、工厂类、读取器以及条件评估等关键概念,使读者能够更全面地掌握Spring的初始化过程。 ... [详细]
  • PHP 实现多级树形结构:构建无限层级分类系统
    在众多管理系统中,如菜单、分类和部门等模块,通常需要处理层级结构。为了高效管理和展示这些层级数据,本文将介绍如何使用 PHP 实现多级树形结构,并提供代码示例以帮助开发者轻松实现无限分级。 ... [详细]
  • 深入解析Java虚拟机(JVM)架构与原理
    本文旨在为读者提供对Java虚拟机(JVM)的全面理解,涵盖其主要组成部分、工作原理及其在不同平台上的实现。通过详细探讨JVM的结构和内部机制,帮助开发者更好地掌握Java编程的核心技术。 ... [详细]
  • 深入解析SpringMVC核心组件:DispatcherServlet的工作原理
    本文详细探讨了SpringMVC的核心组件——DispatcherServlet的运作机制,旨在帮助有一定Java和Spring基础的开发人员理解HTTP请求是如何被映射到Controller并执行的。文章将解答以下问题:1. HTTP请求如何映射到Controller;2. Controller是如何被执行的。 ... [详细]
  • 在高并发需求的C++项目中,我们最初选择了JsonCpp进行JSON解析和序列化。然而,在处理大数据量时,JsonCpp频繁抛出异常,尤其是在多线程环境下问题更为突出。通过分析发现,旧版本的JsonCpp存在多线程安全性和性能瓶颈。经过评估,我们最终选择了RapidJSON作为替代方案,并实现了显著的性能提升。 ... [详细]
  • 深入解析ArrayList与LinkedList的差异
    本文详细对比了Java中ArrayList和LinkedList两种常用集合类的特性、性能及适用场景,通过代码示例进行测试,并结合实际应用场景分析其优缺点。 ... [详细]
  • 由二叉树到贪心算法
    二叉树很重要树是数据结构中的重中之重,尤其以各类二叉树为学习的难点。单就面试而言,在 ... [详细]
  • 深入解析 Android IPC 中的 Messenger 机制
    本文详细介绍了 Android 中基于消息传递的进程间通信(IPC)机制——Messenger。通过实例和源码分析,帮助开发者更好地理解和使用这一高效的通信工具。 ... [详细]
  • 主板IO用W83627THG,用VC如何取得CPU温度,系统温度,CPU风扇转速,VBat的电压. ... [详细]
  • 本文探讨了在Java中如何正确地将多个不同的数组插入到ArrayList中,避免所有数组在插入后变得相同的问题。我们将分析代码中的问题,并提供解决方案。 ... [详细]
  • 深入解析动态代理模式:23种设计模式之三
    在设计模式中,动态代理模式是应用最为广泛的一种代理模式。它允许我们在运行时动态创建代理对象,并在调用方法时进行增强处理。本文将详细介绍动态代理的实现机制及其应用场景。 ... [详细]
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社区 版权所有