二叉树:有了如此高效的散列表,为什么还需要二叉树?

news2024/12/26 23:51:11

文章来源于极客时间前google工程师−王争专栏。

上一节我们学习了树、二叉树以及二叉树的遍历,今天我们再来学习一种特殊的的二叉树,二叉查找树。二叉查找树最大的特点就是,支持动态数据集合的快速插入、删除、查找操作。

我们之前说过,散列表也是支持这些操作的,并且散列表的这些操作比二叉查找树更高效,时间复杂度是 O(1)。既然有了这么高效的散列表,使用二叉树的地方是不是都可以替换成成散列表呢?有没有哪些地方是散列表做不了,必须要用二叉树来做的呢?

二叉查找树(Binary Search Tree)

二叉查找树是二叉树中最常用的一种类型,也叫二叉搜索树。顾名思义,二叉查找树是为了实现快速查找而生的。不过,它不仅仅支持快速插入、删除一个数据。它是怎么做到这些的呢?

这些都依赖于二叉查找树的特殊结构。**二叉查找树要求,在树中的任意一个节点,其左子树中的每个节点的值,都要小于这个节点的值,而右子树节点的值都大于这个节点的值。**二叉查找树结构如下图所示:
image

我们来看二叉查找树是如何实现快速查找、插入、删除操作。

1.二叉查找树的查找操作

首先,我们看如何在二叉查找树中查找一个节点。我们先取根节点,如果它等于我们要查找的数据,那就返回。如果要查找的数据比根节点的值小,那就在左子树中递归查找;如果要查找的数据比根节点的值大,那就在右子树中递归查找。
image

代码实现如下:

public class BinarySearchTree {
  private Node tree;

  public Node find(int data) {
    Node p = tree;
    while (p != null) {
      if (data < p.data) p = p.left;
      else if (data > p.data) p = p.right;
      else return p;
    }
    return null;
  }

  public static class Node {
    private int data;
    private Node left;
    private Node right;

    public Node(int data) {
      this.data = data;
    }
  }
}

2.二叉查找树的插入操作

二叉查找树的插入过程有点类似查找操作。新插入的数据一般都是在叶子节点上,所以我们只需要从根节点开始,依次比较要插入的数据和节点的大小关系。

如果要插入的数据比节点的数据大,并且节点的右子树为空,就将新数据直接插到右子节点的位置;如果不为空,就再递归遍历右子树,查找插入位置。同理,如果要插入的数据比节点数值小,并且节点的左子树为空,就将新数据插入到左子节点的位置;如果不为空,就再递归遍历左子树,查找插入位置。

image

插入代码实现如下:

public void insert(int data) {
  if (tree == null) {
    tree = new Node(data);
    return;
  }

  Node p = tree;
  while (p != null) {
    if (data > p.data) {
      if (p.right == null) {
        p.right = new Node(data);
        return;
      }
      p = p.right;
    } else { // data < p.data
      if (p.left == null) {
        p.left = new Node(data);
        return;
      }
      p = p.left;
    }
  }
}

二叉查找树的查找、插入操作都比较简单易懂,但是它的删除操作就比较复杂了 。针对要删除节点的子节点个数的不同,我们需要分三种情况来处理。

第一种情况是,如果要删除的节点没有子节点,我们只需要直接将父节点中,指向要删除节点的指针置为 null。比如图中的删除节点 55。

第二种情况是,如果要删除的节点只有一个子节点(只有左子节点或者右子节点),我们只需要更新父节点中,指向要删除节点的指针,让它指向要删除节点的子节点就可以了。比如图中的删除节点 13。

第三种情况是,如果要删除的节点有两个子节点,这就比较复杂了。我们需要找到这个节点的右子树中的最小节点,把它替换到要删除的节点上。然后再删除掉这个最小节点,因为最小节点肯定没有左子节(如果有左子结点,那就不是最小节点了),所以,我们可以应用上面两条规则来删除这个最小节点。比如图中的删除节点 18。
image

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1144983.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MODBUS-RTU从站通信(SMART PLC作为MODBUS-RTU从站)

SMART PLC作为MODBUS-RTU主站通信请参考下面文章链接: 【精选】PLC MODBUS通信优化、提高通信效率避免权限冲突(程序+算法描述)-CSDN博客文章浏览阅读2.5k次,点赞5次,收藏10次。MODBUS通讯非常简单、应用也非常广泛,有些老生常谈的问题,这里不再赘述,感兴趣的可以参看…

【394.字符串解码】

目录 一、题目描述二、算法原理三、代码实现 一、题目描述 二、算法原理 三、代码实现 class Solution { public:string decodeString(string s) {stack<string> s1;s1.push("");stack<int> s2;int i 0, n s.size();while (i < n){//1.如果是数字入…

听GPT 讲Rust源代码--library/std(6)

题图来自 Why you should use Python and Rust together[1] File: rust/library/std/src/sys/unix/thread_parking/netbsd.rs 文件netbsd.rs位于Rust源代码的rust/library/std/src/sys/unix/thread_parking目录下。该文件是Rust标准库中用于Unix操作系统的线程等待和唤醒机制的…

如何做好一次代码审查,什么样是一次优秀的代码审查,静态代码分析工具有哪些

代码审查是确保代码质量、提升团队协作效率、分享知识和技能的重要过程。以下是进行优秀代码审查的一些指南&#xff1a; 如何做好代码审查&#xff1a; 理解代码的背景和目的&#xff1a; 在开始审查前&#xff0c;确保你了解这次提交的背景和目的&#xff0c;这有助于更准确…

pycharm运行R语言脚本(win10环境下安装)

文章目录 简介1. pycharm安装插件2. 安装R语言解释器2.1下载安装包2.2具体安装过程 3.编辑环境变量4 检验是否安装成功&#xff1a;5.安装需要的library6.pycharm中配置安装好的R语言解释器 简介 pycharm 安装 R language for Intellij R language for Intellij 是一个插件&am…

SolidWorks2020详细步骤安装教程

SolidWorks 2020 提供了许多增强和改进功能&#xff0c;其中大多数是直接针对客户要求而做出的增强和改进,这些增强功能可以帮助您加速和改进产品开发流程。从概念设计到制造产品&#xff0c;设计、模拟、制造和协作方面的改进让您可以使用新的工作流程来缩短上市时间和提高产品…

雨云OSS服务介绍和使用教程,以及Chevereto图床使用雨云OSS的教程

雨云OSS&#xff08;对象存储&#xff09;服务介绍和使用教程&#xff0c;以及Chevereto图床程序使用雨云OSS的教程 雨云OSS&#xff08;对象存储&#xff09;是一种基于S3协议的云端数据存储服务&#xff0c;它可以帮助你将数据安全、高效地存储在云端&#xff0c;并且可以随…

vue使用WEB自带TTS实现语音文字互转

前言 时隔多日&#xff0c;自己已经好久没更新文章了&#xff1b;今年一直跟随公司的政策[BEI YA ZHA]中&#xff0c;做了一个又一个的需求&#xff0c;反而没有多少自己的时间&#xff0c;更别说突破自己 ˚‧(˚ ˃̣̣̥᷄⌓˂̣̣̥᷅ )‧˚&#xff08;雾&#xff09; 然…

JavaScript_Pig Game切换当前玩家

const current0El document.getElementById(current--0); const current1El document.getElementById(current--1); if (dice ! 1) {currentScore dice;current0El.textContent currentScore;} else {} });这是我们上个文章写的代码&#xff0c;这个代码明显是有问题的&…

图解Kafka高性能之谜(五)

高性能网络模型NIO 简单架构设计&#xff1a; 详细架构设计&#xff1a; 高性能的磁盘写技术 高性能的消息查找设计 索引文件定位使用跳表的设计 偏移量定位消息时使用稀疏索引&#xff1a; 高响应的磁盘拷贝技术 批处理设计 请求亲和性设计 内存池高效、安全设计 高性能…

Spring Boot进阶(91):从零开始,轻松打造Sofa+Spring Boot分布式开发环境

&#x1f4e3;前言 Sofa是一款基于Java语言的分布式架构&#xff0c;它的核心理念是通过将可复用的业务逻辑和服务分离出来&#xff0c;从而提高系统的可维护性和可扩展性。Spring Boot是一款基于Spring框架快速构建应用程序的工具&#xff0c;它拥有丰富的自动化配置和快速开发…

Kibana功能栏中找不到Timelion功能模块的解决

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

Maven入门与开箱即用

一、初识 Maven&#xff08;了解&#xff09; 1、项目遇到的问题 构建&#xff1a;编译代码&#xff0c;运行测试&#xff0c;打包&#xff0c;部署应用&#xff0c;运行服务器等&#xff1b;依赖&#xff1a;项目依赖大量的第三方包&#xff0c;第三方包又依赖另外的包&…

NewStarCTF2023week4-Nmap

题目要我们找出Nmap扫描得到所有的开放端口 Nmap通常用于直接扫描目标主机&#xff0c;而不是直接扫描pcap文件。 那么这里我们还是使用wireshark来分析&#xff0c;使用过滤器&#xff1a; tcp.flags.syn 1 and tcp.flags.ack 1 这个过滤条件可以筛选出TCP端口开放的数据…

使用设计模式基于easypoi优雅的设计通用excel导入功能

文章目录 概要整体架构流程代码设计配置类通用API分发器处理器业务逻辑处理service接口策略模型 小结 概要 基于java原生 easypoi结合适配器模式、策略模式、工厂模式设计一个通用的excel导入框架 整体架构流程 代码设计 由上到下&#xff0c;分别讲解代码 配置类 ExcelCon…

【IO面试题 三】、说说NIO的实现原理

文章底部有个人公众号&#xff1a;热爱技术的小郑。主要分享开发知识、学习资料、毕业设计指导等。有兴趣的可以关注一下。为何分享&#xff1f; 踩过的坑没必要让别人在再踩&#xff0c;自己复盘也能加深记忆。利己利人、所谓双赢。 面试官&#xff1a;说说NIO的实现原理 参…

eclipse安装教程(2021版)

第一步&#xff1a;下载JDK &#xff08;下载地址&#xff09; Java SE - Downloads 第二步 根据自己电脑的系统&#xff0c;选择相应的版本x64代表64位&#xff0c;x86代表32位。点击相应的JDK进行下载 点击之后会出现一个对话框 同意之后下载。(记住下载到哪&#xff0c;打…

二叉树:什么样的二叉树适合用数组来存储?

文章来源于极客时间前google工程师−王争专栏。 前面我们讲的都是线性表结构&#xff0c;栈、队列等等。今天我们讲一种非线性表结构&#xff0c;树。树这种数据结构比线性表的数据结构要复杂得多&#xff0c;内容也比较多&#xff0c;所以我会分四节来讲解。 问题&#xff1…

【Javascript】弹出框

目录 警告框 确认框 提示框 警告框 alert(你好); 确认框 var isConfirm confirm(请确认) console.log( isConfirm); 提示框

基于非侵入式负荷检测与分解的电力数据挖掘

基于非侵入式负荷检测与分解的电力数据挖掘 在这里插入图片描述 **摘要&#xff1a;本案例将根据已收集到的电力数据&#xff0c;深度挖掘各电力设备的电流、电压和功率等情况&#xff0c;分析各电力设备的实际用电量&#xff0c;进而为电力公司制定电能能源策略提供一定的参…