Java-数据结构-Map与Set-(一) ٩(๑>◡<๑)۶

news2024/11/16 21:36:01

文本目录:

❄️一、搜索树:

   ☑ 1、概念:

      ☑ 2、操作-插入:

 代码: 

      ☑ 3、操作-查看:

    代码: 

      ☑ 4、操作-删除:

    代码: 

      ☑ 5、性能分析:

❄️二、搜索:

     ☞ 1、概念和场景:

      ☞ 2、模型:

❄️ 三、Map的使用:

     ▶ 1、关于Map的说明:

     ▶ 2、Map常用的方法:

      ▶ 3、Map使用时候的注意:

❄️四、Set的使用:

     ▶ 1、Set常用的方法:

       ▶ 2、Set使用时候的注意:

❄️总结:


我们呢请出我们的一个老朋友:

   对于这张表呢,我们就只剩下关于Set和Map的这个接口了,而对于这连个接口呢是和我们搜索相关的一个接口,那么在了解Set和Map之前呢,我们来介绍一个新的二叉树——二叉搜索树 

❄️一、搜索树:

   1、概念:

二叉搜索树又称二叉排序树,它或者是空树,如果不是空树就要具备以下的性质:

1、如果它的左子树不为空的话,其所有左子树的节点的值要比根节点小

2、如果它的右子树不为空的话,其所有右子树的节点的值要比根节点大

3、它的左右子树都为二叉搜索树

我们来看一个例子:

这个就是一个二叉搜索树。

我们接下来自实现一下关于二叉搜索树的 插入、查找、删除操作。


在执行操作之前呢,我们先把其准备工作准备好,我们要设置我们二叉搜索树的节点和其根节点:

public class BinarySearchTree {

    static class TreeNode {
        public int val;
        public TreeNode left;
        public TreeNode right;

        public TreeNode(int val) {
            this.val = val;
        }
    }

    public TreeNode root;
}

      2、操作-插入:

我们的插入呢就是非常的简单了,我们要进行以下操作:

1、判断是否是空。如果是空树,第一个节点就是根结点。

2、不为空的时候,我们定义一个 parent 和 cur 临时变量。parent 用来存储 cur 的根节点,cur 用        来遍历二叉搜索树,来寻找要插入的地方。

3、每次走 cur 这前呢,执行 parent = cur ,为了把 cur 的父亲节点记录下来

4、我们要判断每一个 cur.val 和 我们插入的 val 值大小:

      如果 cur.val < val 执行 cur = cur.right

      如果 cur.val > val 执行 cur = cur.left

这个操作是循环的,直至我们的 cur == null 的时候呢,就跳出循环。

这里要注意:我们的二叉搜索树是不能存储两个相同的节点的。

5、这个时候我们的 parent 这个节点就是 cur 的父亲节点,之后再次比较 parent.val 和 val 的值

    如果 parent.val > val 执行 parent.left = val这个值的节点

    如果 parent.val < val 执行 parent.right = val这个值的节点

 代码: 

public void insert(int val) {
        if (root == null) {
            root = new TreeNode(val);
            return;
        }

        TreeNode newNode = new TreeNode(val);
        TreeNode parent = null;
        TreeNode cur = root;

        while (cur != null) {
            if (cur.val < val) {
                parent = cur;
                cur = cur.right;
            } else if (cur.val > val) {
                parent = cur;
                cur = cur.left;
            }else {
                //不能存在相同的节点
                return;
            }
        }

        if (parent.val < val) {
            parent.right = newNode;
        }else {
            parent.left = newNode;
        } 
    }


      3、操作-查看:

这个方法就很简单了,我们只需要进行和要查找的 val 进行比较就可以了

1、定义一个 cur 的临时变量存储 root 用于遍历

2、用 cur.val 和 val 值进行比较

      如果 cur.val < val 执行 cur = cur.right

      如果 cur.val > val 执行 cur = cur.left

      如果 cur.val = val 我们直接返回 cur 这个节点就可以了

我们直接来看代码: 

    代码: 

public TreeNode search(int val) {
        if (root == null) {
            return null;
        }

        TreeNode cur = root;

        while (cur != null) {
            if (cur.val < val) {
                cur = cur.right;
            } else if (cur.val > val) {
                cur = cur.left;
            } else {
                return cur;
            }
        }
        return null;
    }

      4、操作-删除:

     删除呢,我们需要先找到我们要删除的节点,这里我们使用 cur 来设为要删除的节点的,用 parent 来记录我们要删除的节点的父亲节点。在我们找到要删除的节点节点之后呢,我们对于删除操作有几种不同的情况,我们来看看:

1、cur.left == null 时

     如果:cur == root 执行 root = cur.right

     如果:parent.left == cur 执行 parent.left = cur.right

     如果:parent.right == cur 执行 parent.right =  cur.right

2、cur.right == null 时

     如果:cur == root 执行 root = cur.left

     如果:parent.left == cur 执行 parent.left = cur.left

     如果:parent.right == cur 执行 parent.right = cur.left

3、cur.left  != null && cur.right != null

我们先设置 target 存储 cur.right,targetParent = cur 

我们这个时候呢有两个方法做到删除操作,

     其一:在左树中找到最大值(左树中的最右边的节点)

     其二:在右数中找到最小值(右树中的最左边的节点)

先用其中一个,之后呢执行 cur.val = target.val

之后我们还要进行判断

     如果:targetParent.left == target 执行 targetParent.left = target.right

     如果:targetParent.right == target 执行 targetParent.right = target.right

这里我演示的使用的在左树中找最大值

我们来看看这个整体的代码的编写: 

    代码: 

public void remove(int val) {
        if (root == null) {
            return;
        }
        TreeNode parent = null;
        TreeNode cur = root;
        while(cur != null) {
            if (cur.val < val) {
                parent = cur;
                cur = cur.right;
            } else if (cur.val > val) {
                parent = cur;
                cur = cur.left;
            } else {
                removeNode(parent,cur);
            }
        }
    }

    private void removeNode(TreeNode parent, TreeNode cur) {
        if (cur.left == null) {
            if (cur == root) {
                root = cur.right;
            } else if (parent.left == cur) {
                parent.left = cur.right;
            } else {
                parent.right = cur.right;
            }
        } else if (cur.right == null) {
            if (cur == root) {
                root = cur.left;
            } else if (parent.left == cur) {
                parent.left = cur.left;
            } else {
                parent.right = cur.left;
            }
        } else {
            TreeNode targetParent = cur;
            TreeNode target = cur.right;
            while (target.left != null) {
                targetParent = target;
                target = target.left;
            }
            cur.val = target.val;
            if (targetParent.left == target) {
                targetParent.left = target.right;
            } else {
                targetParent.right = target.right;
            }
        }
    }

      5、性能分析:

最好的情况下:二叉树趋于完全二叉树,这样平均比较次数为:logN

最坏的情况下:二叉树为单分支,这样平均比较次数为:N/2


❄️二、搜索:

      1、概念和场景:

     我们要介绍的Map 和 Set 呢是一种专门用来搜索的容器或者数据结构,其搜索的效率和具体的实例化子类有关系。

     以前的我们的搜索方式有:

  1、直接遍历:时间复杂度为O(N),当数据多的时候就会更慢。

  2、二分查找:时间复杂度为O(logN),但是搜索的序列必须是有序的。

上面的这些呢,是比较适合进行 静态查找 的,一般不会在查找的时候进行插入和删除操作了。

     那么我们有时候就需要在查找的时候进行 插入或者是删除 操作了,这就是 动态查找 了,这次我们要介绍的 Map和Set 就是一种适合 动态查找 的集合容器了。


      2、模型:

    一般情况下,我们把要搜索的数据称为 关键字(key) ,和关键字对应的称为 值(value),将其称为 key-value 键值对,所以模型会有两种:

 1、key-value 模型,比如:

      统计文件中 每个但出现的次数,<单词,单词出现的次数>

 2、纯 key 模型,比如:

      快速查找某个单词是否在文件中。

我们将要介绍的 Map是key-value 模型,而 Set是纯key 模型。 


❄️ 三、Map的使用:

         Map的官方文档

     ▶ 1、关于Map的说明:

     对于 Map 是一个接口,该类是没有继承 Collection 这个接口的,该类中存储的是 <K,V>模型,并且这里的 K 一定是唯一的,不能重复。


     2、Map常用的方法:

    因为我们的 Map 是一个接口,所以不能实例化对象,所以需要我们使用 TreeMap 和 HashMap 来实例化对象。

      我们的 TreeMap 的底层使用的是 红黑树 是我们上面介绍的二叉搜索树的一种,所以我们的才会介绍 二叉搜索树 。而 HashMap 的底层是 哈希桶 ,这个我们后面会介绍 Hash。


V put(K key,V value)设置 key 所对应的 value 值

我们来看看如何使用的: 

这个呢就是我们的Map中的 put 方法,当然这里也可以吧Map替换成 TreeMap 或者 HashMap。 


V get(Object key)返回传入的 key 所对应的 value 值

   这里没有我们的 key 值,我们呢应该返回null 但是呢,我们如果对null 进行拆箱操作的话呢,就会出现空指针异常,所以我们这里要使用 Integer 来接收,就不会出现空指异常。


V getOrDefault(Object key,V defaultValue) 返回 key所对应的 value 值,如果key不存在,返回默认值。


V remove(Object key)删除 key 所对应的映射关系


boolean containsKey(Object key)判断是否包含 key 
boolean containsValue(Object value)判断是否包含 value 


    我们接下来介绍几个特殊的 Map 方法,这些方法中使用到了 Set 这个接口,Set 呢是不能存储相同的数据的这里要注意。

Set<K> keySet()返回所有的不重复的 key 的集合,放到Set 集合中


Collection<V> values()判断是否包含 key 


Set<Map.Entry<K,V>> entrySet()返回所有的 key-value 的映射关系 

    我们这里的 Map.Entry 就是我们的搜索树的每一个节点,这里面呢有 getValue()得到 value 值 ,getKey()得到 key 值,setValue(V value) 这个是将其 value 替换为指定的 value 值。


      3、Map使用时候的注意:

1):

         Map 是一个接口不能直接实例化对象,如果想要实例化对象呢,我们只能实例化其实例类TreeMap 或者是 HashMap 


2):

          Map 中存放的键值对的 key 是唯一的不能重复,而 value 是能进行重复的。


3):

         在TreeMap 中我们插入对象的时候呢,key 不能为空,否则抛空指针异常。但是我们的 value 可以为空,但是在 HashMap 中呢 都可以为空。


4):

       Map 中的 key可以分离出来存放到 Set 中,因为不能重复。


5):

        Map 中的 value 也可以分离出来存放到 Collection 中,因为可以出现重复的值,所以不能存放到 Set 中。


6):

        当 key 的值出现重复的时候呢,我们的key 映射的 value 值是后出现的值。


7):

        我们的 存放的时候呢,我们是根据 key 进行比较来确定存放顺序的,不是根据 value 来确定的存放顺序的。


❄️四、Set的使用:

         Set的官方文档


     我们的 Set 和 Map 是不同的,我们的 Set 是继承自 Collection 的接口的,并且Set 中只存储 key值。


     1、Set常用的方法:

boolean add(E e)添加元素,但是不会添加重复的元素
boolean contains(Object o)判断 o 是否出现在 Set 集合中
boolean remove(Object o)删除集合中的 o


Iterator<E> iterator()返回迭代器

 我们的 Map 是不能使用迭代器的,但是呢我们可以使用Set 来间接使用迭代器遍历Map :


int size()

返回Set 中的元素个数

boolean isEmpty()判断set是否为空
Object[ ] toArray将 set 中的元素转换为数组返回
boolean containsAll(Collection<?> c)集合 c 中的元素是否在set中全部存在
boolaen addAll(Collecton<?> c)将集合 c 中的元素存放到set集合中,可以达到去重的效果

       2、Set使用时候的注意:

1):

         Set 是继承 Collection 的一种接口


2):

        Set 只存储了 key,并且key 要唯一


3):

       TreeSet 的底层使用的是 Map 来实现的,其使用key 与 Object 的一个默认对象作为键值对插入 Map 中。


4):

       Set 最大的功能就是对元素进行去重操作


5):

       实现 Set 接口的类有 TreeSet 和 HashSet,还有一个LinkedHashSet,这个是在HashSet 的基础上有一个 双向链表 来记录元素的插入顺序。


❄️总结:

    OK,但这里我们的 Set 和 Map 的有关知识的一部分就到这里就结束了,在下一篇博客中会介绍关于 哈希 的一些知识,并且自实现一下 哈希表。让我们尽情期待吧!!!拜拜~~~

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

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

相关文章

如何在Ubuntu上查看和刷新DNS缓存

DNS缓存是用于DNS查找的临时存储系统&#xff0c;负责将域名转换为IP地址。进行DNS查询时&#xff0c;系统会检查缓存中的相关信息。如果找到了&#xff0c;那么它会加速域名解析的过程。如果DNS缓存中的数据过时或不正确&#xff0c;则需刷新它以确保使用正确的信息。本文主要…

自己掏耳朵怎么弄干净?双十一必买的四大可视挖耳勺分享

我们在掏耳朵时是不是老是觉得要么掏不干净&#xff0c;要么太进去了弄到痛耳朵。因为耳道属于我们一个盲区&#xff0c;在使用棉签或者普通耳勺容易因为操作不当弄伤耳膜。可能还会照成不可逆的后果。所以自己在掏耳勺更加推荐大家使用可视挖耳勺会更加干净和安全。那么&#…

【MATLAB代码】二维环境下的RSSI定位程序,自适应锚点数量,带图像输出、坐标输出、中文注释

程序描述 MATLAB编写的RSSI定位程序&#xff0c;自适应锚点数量&#xff0c;带图像输出、坐标输出、中文注释。 功能概述&#xff1a; 本程序实现了在二维平面上通过接收信号强度指示&#xff08;RSSI&#xff09;进行定位的功能。它使用多个锚节点的信号强度测量来估计未知…

CSS链接

链接是网站的重要组成部分&#xff0c;几乎在每个网页上都能看到不少的链接&#xff0c;合理的设计链接的样式能够给网页的颜值加分。链接有四种不同的状态&#xff0c;分别是 link、visited、active 和 hover&#xff0c;可以通过以下伪类选择器来为链接的四种状态设置不同的样…

CentOS8使用chrony同步网络时间

文章目录 引言I CentOS8使用chrony网络时间同步安装chrony配置间同步服务器地址检查本机的时区设置时区chronyc命令II windows网络时间同步2.1 修改同步服务器2.2 修改同步频率引言 应用场景: 获取服务器时间进行船舶在线率统计 dtos.forEach(item -> {if(item.getDwtime(…

红绿灯倒计时读秒数字识别系统源码分享

红绿灯倒计时读秒数字识别检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of …

数据结构——初识树和二叉树

线性结构是一对一的关系&#xff0c;意思就是只有唯一的前驱和唯一的后继&#xff1b; 非线性结构&#xff0c;如树形结构&#xff0c;它可以有多个后继&#xff0c;但只有一个前驱&#xff1b;图形结构&#xff0c;它可以有多个前驱&#xff0c;也可以有多个后继。 树的定义…

kubeadm部署k8s集群,版本1.23.6;并设置calico网络BGP模式通信,版本v3.25--未完待续

1.集群环境创建 三台虚拟机&#xff0c;一台master节点&#xff0c;两台node节点 (根据官网我们知道k8s 1.24版本之后就需要额外地安装cri-dockerd作为桥接才能使用Docker Egine。经过尝试1.24后的版本麻烦事很多&#xff0c;所以此处我们选择1.23.6版本) 虚拟机环境创建参考…

【LeetCode】动态规划—63. 不同路径 II(附完整Python/C++代码)

动态规划—63. 不同路径 II 前言题目描述基本思路1. 问题定义:2. 理解问题和递推关系:3. 解决方法:3.1 动态规划方法3.2 空间优化的动态规划 4. 进一步优化:5. 小总结: 代码实现Python3代码实现Python 代码解释C代码实现C 代码解释 总结: 前言 本文将探讨“不同路径 II”这一问…

线性跟踪微分器TD详细测试(Simulink 算法框图+CODESYS ST+博途SCL完整源代码)

1、ADRC线性跟踪微分器 ADRC线性跟踪微分器(ST+SCL语言)_adrc算法在博途编程中scl语言-CSDN博客文章浏览阅读784次。本文介绍了ADRC线性跟踪微分器的算法和源代码,包括在SMART PLC和H5U平台上的实现。文章提供了ST和SCL语言的详细代码,并讨论了跟踪微分器在自动控制中的作用…

深入理解 Nuxt.js 中的 app:error 钩子

title: 深入理解 Nuxt.js 中的 app:error 钩子 date: 2024/9/27 updated: 2024/9/27 author: cmdragon excerpt: 摘要:本文深入讲解了Nuxt.js框架中的app:error钩子,介绍其在处理web应用中致命错误的重要作用、使用方法及实际应用场景。通过创建Nuxt项目、定义插件、触发…

基于nodejs+vue的水产品销售管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

Could not find com.mapbox.mapboxsdk:mapbox-android-accounts:0.7.0.解决

AndroidStudio编译APK出现如下错误&#xff1a; Could not find com.mapbox.mapboxsdk:mapbox-android-accounts:0.7.0. 出现上面错误原因是因为没有打开对应的仓库导致的&#xff0c; 手动添加如下创建地址可解决&#xff1a; maven { url https://maven.aliyun.com/repos…

vue项目中的node、node-sass、sass-loader之间的版本关系

这个报错&#xff0c;想必大部分人都会遇到&#xff0c;版本不适配的问题&#xff0c;记录下解决方案。 版本适配问题 node 与node-sass node-sass与sass-loader sass-loader 4.1.1&#xff0c;node-sass 4.3.0sass-loader 7.0.3&#xff0c;node-sass 4.7.2sass-loader 7.3.…

dify新特性:并行agent/工作流开发与变量存储

大模型相关目录 大模型&#xff0c;包括部署微调prompt/Agent应用开发、知识库增强、数据库增强、知识图谱增强、自然语言处理、多模态等大模型应用开发内容 从0起步&#xff0c;扬帆起航。 再谈Agent&#xff1a;Dify智能体实现Txet2SQLMoe模式&#xff1a;或将是最好的大模…

UE5: Content browser工具编写

Extend content browser 创建自定义菜单入口的步骤&#xff1a;create custom menu entry. steps: Load content browser module -> PathViewContextMenuExtenders -> Add in our own delegate -> Bind to our own member functions 基础概念&#xff08;本文实…

C++【类和对象】(拷贝构造与运算符重载)

1. 拷贝构造 如果⼀个构造函数的第⼀个参数是自身类类型的引用&#xff0c;且任何额外的参数都有默认值&#xff0c;则此构造函数也叫做拷贝构造函数&#xff0c;也就是说拷贝构造是⼀个特殊的构造函数。 注意&#xff1a;拷贝构造是用一个已经实例化的对象来初始化一个新对象…

中级职称评审到底需要准备什么材料?

职称评审需要的材料非常非常多&#xff0c;其中涉及到各类表格&#xff0c;这些小资料&#xff0c;看起来简单&#xff0c;实则做起来复杂&#xff0c;不过这种资料只能当年通知出来之后进行整理&#xff0c;今天甘建二跟大家说一下职称评审中需要提前准备的一些重要材料&#…

5.10直方图均衡化

基本概念 直方图均衡化&#xff08;Histogram Equalization&#xff09;是一种常用的图像处理技术&#xff0c;用于改善图像的对比度。通过调整图像中像素值的分布&#xff0c;直方图均衡化可以使图像的动态范围更广&#xff0c;从而增强图像的细节可见度。 直方图均衡化原理…