Map和Set,TreeMap和TreeSet,HashMap和HashSet

news2024/12/23 18:04:22

文章目录

  • TreeSet和TreeMap
    • 二叉搜索树模拟TreeMAp
      • 定义
    • 基本操作
      • 插入
      • 查找
      • 删除(难点)
      • 遍历
      • 性能分析
      • 应用场景
  • Map&&Set
    • 模型
  • HashMap
    • 常用方法
  • HashSet
    • 常用方法
      • HashMap和HashSet区别
        • 数据结构不同
        • 元素类型不同
        • 方法不同
        • 使用场景不同

TreeSet和TreeMap

定义:

TreeSet是Java集合框架中的一种有序集合,它实现了Set接口,因此具有不允许重复元素的特性。与HashSet不同,TreeSet使用红黑树数据结构来存储元素,这使得元素在集合中保持有序

TreeMap是基于红黑树数据结构的键值对映射。它保证键的有序性,键按照其自然顺序(通过键的compareTo方法确定的顺序)进行排序。

联系:TreeSet的底层是TreeMap,TreeMap的底层是一颗红黑树,而红黑树是一颗近似平衡的二叉搜索树

二叉搜索树模拟TreeMAp

定义

是一颗特殊的二叉树,具有以下性质:

  1. 若左子树不为空,则左子树上的所有节点的值都小于根节点的值
  2. . 若右子树不为空,则右子树上的所有节点的值都大于根节点的值
  3. 左右子树也都是二叉搜索树
  4. 不存在键值相等的节点
    在这里插入图片描述
static class TreeNode{
        public int val;
        public TreeNode left;
        public TreeNode right;

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

基本操作

插入

  1. 如果是空树,直接插入
  2. 如果不是空树,创建新节点,比较根节点的值
  3. 如果新节点的键小于根节点的键,则将新节点插入到根节点的左子树中。
  4. 如果新节点的键大于根节点的键,则将新节点插入到根节点的右子树中
//插入
    //定义一个parent
    public void insert(int key){
        if(root==null){
            root=new TreeNode(key);
            return ;
        }
        TreeNode parent=null;
        TreeNode cur=root;
        TreeNode node=new TreeNode(key);
        while(cur!=null){
            if(cur.val<key){
                //先让parent到cur的位置,后cur往后走
                parent=cur;
                cur=cur.right;
            }else if(cur.val==key){
                //不能插入两个相同的数
                return;
            }else {
                parent=cur;
                cur=cur.left;
            }
        }
        //走到这里说明要开始插入了,比较子树上根节点与要插入的值
        if(parent.val<key){
            parent.right=node;
        }else{
            parent.left=node;
        }
    }

查找

  1. 从根节点开始比较。
  2. 如果查找的键小于当前节点的键,则递归地在左子树中查找
  3. 如果查找的键大于当前节点的键,则递归地在右子树中查找
  4. 如果找到节点,则返回该节点
  5. 如果没有找到,则返回null。
public TreeNode search(int key) {
        TreeNode cur=root;
        while(cur!=null){
           if(cur.val<key){
               cur=cur.right;
           }else if(cur.val==key){
               return cur;
           }else{
               cur=cur.left;
           }
        }
        return null;
    }

删除(难点)

(1) cur.left==null

cur为root,则root=cur.right
在这里插入图片描述

cur不为root,cur是parent.left,则parent.left=cur.right
在这里插入图片描述

cur不为root,cur是parent.right,则parent.right=cur.right
在这里插入图片描述

(2) cur.right==null

cur为root,则root=cur.left
在这里插入图片描述

cur不为root,cur是parent.left,则parent.left=cur.left
在这里插入图片描述

cur不为root,cur是parent.right,则parent.right=cur.left
在这里插入图片描述

(3)cur的左右侧都不为空,需要进行替换法删除

定义tp=cur,target,右树的找到最小值,右树最左边的节点,最左边的节点说明左树为空

public boolean remove(int key){
        TreeNode cur=root;
        TreeNode parent=null;
        //parent要记录下cur的前一个节点,要不然删不了
        while(cur!=null){
            if(cur.val<key){
                parent=cur;
                cur=cur.right;
            }else if(cur.val>key){
                parent=cur;
                cur=cur.left;
            }else {
                removeNode(parent,cur);
                return true;
            }
        }
        return false;
       }

    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(root==cur){
                root=cur.left;
            }else if(parent.left==cur){
                parent.left=cur.left;
            }else {
                parent.right=cur.left;
            }
        }else{//cur的左右都不为空,替换删除
            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;
            }
        }
    }

遍历

二叉搜索树的遍历操作与普通二叉树相同,可以使用前序、中序和后序遍历。

前序遍历举例

  public void prevOreder(TreeNode root){
        if (root==null){
            return;
        }
        prevOreder(root.left);
        System.out.print(root.key+" ");
        prevOreder(root.right);
    }

注意:

  1. 如果TreeMap实现排序,那么存放的对象如果是引用类型那么就必须要实现Comparable或者Comparator接口如果没有实现就会报错,因为无法比较两个对象的大小.

  2. 在TreeMap插入键值对时,key不能为null,否则或抛出NullPointerException异常,value可以为空

性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。
对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。

最优情况下,二叉搜索树为完全二叉树,其平均比较次数为:log以2为底N
最差情况下,二叉搜索树退化为单支树,其平均比较次数为:N/2

应用场景

TreeMap的应用场景
在实际应用中,如果你需要一个有序的映射表,并且不允许键重复,那么TreeMap是一个很好的选择。它既满足了有序性的需求,又提供了高效的操作性能

  • 需要保持键的有序性且需要根据键快速查找值
  • 常用于需要按照特定顺序处理键值对的情况。

TreeSet的应用场景
适用于需要保持元素有序并且去除重复元素的场景。由于其基于红黑树实现,可以高效地支持元素的查找、插入和删除操作。因此,在需要有序集合且不允许重复元素的情况下,TreeSet是一个十分实用的选择

  • 当需要保持元素的有序性且不允许重复
  • 常用于需要按照特定顺序处理元素的情况。

Map&&Set

Map和set是一种专门用来进行搜索的容器或者数据结构,其搜索的效率与其具体的实例化子类有关

常见的搜索方式:
直接遍历,时间复杂度为O(N),元素如果比较多效率会非常慢

二分查找,时间复杂度为O(logN) ,但搜索前必须要求序列是有序的

上述排序比较适合静态类型的查找,即一般不会对区间进行插入和删除操作了,而现实中的查找比如:

  1. 根据姓名查询考试成绩
  2. 通讯录,即根据姓名查询联系方式
  3. 不重复集合,即需要先搜索关键字是否已经在集合中

可能在查找时进行一些插入和删除的操作,即动态查找,那上述两种方式就不太适合了,下面介绍的Map和Set是一种适合动态查找的集合容器

模型

一般把搜索的数据称为关键字(Key),和关键字对应的称为值(Value),将其称之为Key-value的键值对,所以模型会有两种:

  1. 纯 key 模型,比如:
    有一个英文词典,快速查找一个单词是否在词典中,这个单词就是Key
  2. Key-Value 模型,比如:
    统计文件中每个单词出现的次数,统计结果是每个单词都有与其对应的次数:<单词,单词出现的次数>

Map中存储的就是key-value的键值对
Set中只存储了Key。

在这里插入图片描述

Map是一个接口类,该类没有继承自Collection,该类中存储的是<K,V>结构的键值对,并且K一定是唯一的,不
能重复。

注意:Map是一个接口,不能直接实例化对象,如果要实例化对象只能实例化其实现类TreeMap或者HashMap

Set是继承自Collection的接口类,Set中只存储了Key

实现 Set 接口的常用类有 TreeSet 和 HashSet ,还有一个 LinkedHashSet

LinkedHashSet 是在 HashSet 的基础上维护了一个双向链表来记录元素的插入次序,本质上还是HashMap

区别:map带有伴随数据,set没有伴随数据并且能去重

HashMap

常用方法

在这里插入图片描述
关于Entry<K,V>说明:

查看源码可知,Entry是Map接口的一个内部接口
在这里插入图片描述

HashMap实现了Map接口,必然也实现了Entry接口
在这里插入图片描述

可以看到在HashMap的内部类中,提供了获取Key,value的方法以及设置value的方法,没有设置Key的方法
在这里插入图片描述

注意

  1. HashMap存放键值对的Key是唯一的,value是可以重复的

  2. HashMap中的key可以全部分离出来,存储到Set中来访问(因为key不能重复),即keySet()方法.

在这里插入图片描述
在这里插入图片描述

  1. HashMap中的value也可以全部分离出来,存储在Collection中(value可能有重复),即 values()方法.
    在这里插入图片描述
    在这里插入图片描述

  2. entrySet()方法的使用:

    entrySet()方法就是把HashMap中的每个键值对打包成一个整体,然后放入到一个集合中
    在这里插入图片描述
    在这里插入图片描述

HashSet

常用方法

在这里插入图片描述
注意

  1. HashSet中只存储了key,并且key不会重复

  2. 每个构造方法都会初始化一个HashMap
    在这里插入图片描述

  3. HashSet底层HashMap的每个value都是一个空的Object类型的对象
    在这里插入图片描述

  4. HashSet中的key不能修改,如果要修改,需要先删除再重新插入.

  5. HashMap和HashSet的key和value都可以存放null.

在这里插入图片描述
在这里插入图片描述

HashMap和HashSet区别

  1. HashSet是继承自Collection的接口类,Set中只存储key。

  2. HashMap是继承于Map接口,存储的是key-value键值对。

数据结构不同

HashSet: HashSet 内部使用哈希表(或哈希集合)来存储元素。哈希表是一个无序的数据结构,元素之间没有特定的顺序。

HashMap: HashMap 内部也使用哈希表,但它存储键值对,其中键和值之间有关联关系。HashMap 具有键的集合和值的集合,键是唯一的,值可以重复。

元素类型不同

HashSet: HashSet 存储的是单一的元素类型,如整数、字符串等。它用于存储不重复的对象,通过元素的哈希码来判断重复性。

HashMap: HashMap 存储键值对,键和值可以是不同类型的对象。键用于检索值,每个键都必须是唯一的,值可以重复。

方法不同

HashSet: HashSet 提供了添加、删除、查找元素的方法,例如 add(), remove(), contains() 等。它没有提供根据键查找值的方法。

HashMap: HashMap 提供了添加键值对、删除键值对、根据键查找值的方法,例如 put(), remove(), get() 等。它可以根据键来查找对应的值。

使用场景不同

HashSet 的适用场景
数据去重:当你需要存储一组数据,但不关心顺序和关联信息,只关心数据是否重复时,使用 HashSet 是合适的。
例如,存储一组唯一的用户名或标签。

集合运算:HashSet 适合用于集合运算
比如求交集、并集、差集等。

HashMap 的适用场景
键值存储:当你需要将数据与关联的键一起存储时,使用 HashMap 是合适的。
例如,存储学生的成绩,其中学生名是键,成绩是值。

数据索引:HashMap 适合用于构建索引,提供快速的查找能力。
例如,建立一个电话簿,根据姓名查找电话号码。

需要键值对的功能:如果你需要存储关联数据,并且需要使用键来查找值、替换值或遍历键值对,那么 HashMap 是最好的选择。

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

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

相关文章

个人健康档案管理系统

基于springbootvue实现的个人健康档案管理系统&#xff08;源码L文ppt&#xff09;4-076 4.1 系统功能结构设计 根据对个人健康档案管理系统的具体需求分析&#xff0c;把系统可以划分为几个不同的功能模块&#xff1a;管理员可以对系统首页、用户管理、健康体检管理、疫…

智能密码、指纹锁语音芯片ic方案 可存放40s语音内容 NVD语音芯片

随着科技的飞速发展&#xff0c;智能家居安全领域迎来了前所未有的变革。智能密码与指纹锁作为现代家庭安全防护的重要一环&#xff0c;其背后的语音芯片IC开发更是这一变革中的关键技术突破。 智能密码、指纹锁语音芯片ic方案 选型与简介&#xff1a; NVD语音芯片是一款低成…

基于JAVA+SpringBoot+Vue的疫苗发布和接种预约系统

基于JAVASpringBootVue的疫苗发布和接种预约系统 前言 ✌全网粉丝20W,csdn特邀作者、博客专家、CSDN[新星计划]导师、java领域优质创作者,博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java技术领域和毕业项目实战✌ &#x1f345;文末附源码下载链接&#x1f3…

AlmaLinux 安裝JDK8

在 AlmaLinux 上安装 JDK 8 可以通过包管理器 dnf 来完成。AlmaLinux 是基于 RHEL 的一个开源发行版&#xff0c;因此其包管理系统和 RHEL 类似。以下是详细的步骤来安装 OpenJDK 8 1. 更新系统包列表 sudo dnf update -y 2. 安装 OpenJDK 8 使用 dnf 安装 OpenJDK 8。你可…

【Python-tkinter】实现简单的文本编辑器(附带教程源码)

如果你也是刚入门的小伙伴呢&#xff0c;小编为你们准备了入门Python学习籽料和Python入门实践&#xff0c;点击领取&#xff08;无偿获得&#xff09; 利用tkinter实现简单的文本编辑器。创建一个简单的文本编辑器。可以用读文件的方式在一个文本域里显示一些文字供用户编辑…

大模型分布式训练并行技术(七)-自动并行

近年来&#xff0c;随着Transformer、MOE架构的提出&#xff0c;使得深度学习模型轻松突破上万亿规模参数&#xff0c;传统的单机单卡模式已经无法满足超大模型进行训练的要求。因此&#xff0c;我们需要基于单机多卡、甚至是多机多卡进行分布式大模型的训练。 而利用AI集群&a…

5--苍穹外卖-SpringBoot项目中菜品管理 详解(一)

目录 公共字段自动填充 问题分析 实现思路 代码开发 步骤一 步骤二 功能测试 新增菜品 需求分析和设计 代码开发 文件上传接口 功能测试 1--苍穹外卖-SpringBoot项目介绍及环境搭建 详解-CSDN博客 2--苍穹外卖-SpringBoot项目中员工管理 详解&#xff08;一&#…

医疗器械库存管理软件 符合gsp要求

软件介绍&#xff1a; 盘谷医疗器械进销存管理软件契合医疗器械行业特点&#xff0c;符合gsp要求&#xff0c;专为一二三类医疗器械经营企业开发的医疗器械进销存、质量验收、GSP管理、UDI扫码识别、财务管理一体化经营管理系统&#xff0c;符合药监新版医疗器械经营质量管理规…

C++在线开发环境搭建(WEBIDE)

C在线开发环境搭建 一、环境说明1.1 系统基础环境说明1.1 docker-ce社区版安装 二、codeserver构建2.1 构建codeserver环境的docker容器2.2 构建docker镜像2.3 运行docker2.4 运行展示 三、构建codeserver中的c开发环境3.1 插件下载3.2 插件安装 四、其他知识4.2 code-server配…

vue仿chatGpt的AI聊天功能--大模型通义千问(阿里云)

vue仿chatGpt的AI聊天功能–大模型通义千问&#xff08;阿里云&#xff09; 通义千问是由阿里云自主研发的大语言模型&#xff0c;用于理解和分析用户输入的自然语言。 1. 创建API-KEY并配置环境变量 打开通义千问网站进行登录&#xff0c;登陆之后创建api-key&#xff0c;右…

20个数字经济创新发展试验区建设案例【2024年发布】

数据简介&#xff1a;国家数字经济创新发展试验区的建设是一项重要的国家战略&#xff0c;旨在推动数字经济与实体经济的深度融合&#xff0c;促进经济高质量发展。自2019年10月启动以来&#xff0c;包括河北省&#xff08;雄安新区&#xff09;、浙江省、福建省、广东省、重庆…

【java】前端RSA加密后端解密

目录 1. 说明2. 前端示例3. 后端示例3.1 pom依赖3.2 后端结构图3.3 DecryptHttpInputMessage3.4 ApiCryptoProperties3.5 TestController3.6 ApiCryptoUtil3.7 ApiDecryptParamResolver3.8 ApiDecryptRequestBodyAdvice3.9 ApiDecryptRsa3.10 ApiCryptoProperties3.11 KeyPair3…

一天面了8个Java后端,他们竟然还在背5年前的八股文!

今天面了8个Java候选人&#xff0c;在面试中我发现他们还停留在面试背八股文的阶段&#xff0c;5年前面试背八股文没问题&#xff0c;随着市场竞争越来越激烈&#xff0c;再问普通的Java八股文已经没有意义了&#xff0c;因为考察不出来获选人的真实实力&#xff01; 现在面试…

VIGOSERVO帝人伺服驱动器维修ARN135-F ARS135-25

帝人VIGOSERVO驱动器维修TEIJIN SEIKI伺服驱动器全系列型号修理。 关于VIGOSERVO伺服驱动器维修的相关内容&#xff0c;可以归纳为以下几个方面&#xff1a; 一、维修概述 VIGOSERVO伺服驱动器作为自动化设备组件&#xff0c;多应用于工业机器人、数控加工等高精度传动系统中…

【大数据】大数据运维方案浅析总结

1. 引言 在大数据时代&#xff0c;如何高效管理和维护大规模数据平台&#xff0c;成为许多企业面临的重要挑战。本文将对市面上一些流行的大数据运维管理方案进行全面分析&#xff0c;包括Cloudera的CDH和CDP、Hortonworks的HDP、Apache的Ambari、国产开源平台Datasophon&#…

docker使用阿里云镜像加速

官方教程 https://help.aliyun.com/zh/acr/user-guide/accelerate-the-pulls-of-docker-official-images 申请地址 https://free.aliyun.com/?searchKey%E9%95%9C%E5%83%8F 阿里云容器镜像服务地址 https://cr.console.aliyun.com/cn-zhangjiakou/instances 展开才能看到

UNI-SOP应用场景(2)- 业务平台集成

前面介绍了项目前期我们前端可以不需要业务平台参与就可以开始开发&#xff0c;这一章我们介绍新业务平台怎么集成到UNI-SOP云统一认证中心。 新建项目引入uni-client在云认证统一管理端新增业务平台在业务平台项目配置在认证中心创建的平台信息接口开发和权限校验 新建项目 打…

浅谈端到端,助力智能驾驶突破OR错误路线

目前端到端自动驾驶的定义可以简单分为狭义端到端和广义端到端。 狭义端到端&#xff1a;传感器数据进入神经 网络处理后&#xff0c;直接输出方向盘、油门、刹车等执行器的控制信号&#xff0c;该模式通过单一神经网络模型实现&#xff0c;是严格意义上的端到端。 广义端到端&…

基于nodejs+vue的外卖管理系统

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

【科普知识】什么是驱控一体化伺服电机?

驱控一体化伺服电机以其高度的集成性、兼容性、便捷性以及卓越的性能表现&#xff0c;成为了现代工业自动化领域的一颗璀璨明珠。对于那些追求高效、精准、智能控制的行业用户而言&#xff0c;它无疑是一种理想的选择。 一、驱控一体化伺服电机是什么 驱控一体化伺服电机&…