数据结构:Map Set(一)

news2025/4/16 22:53:57

目录

一、搜索树

1、概念

2、查找

3、插入

4、删除

二、搜索

1、概念及场景

2、模型

(1)纯key模型

(2)Key-Value模型

三、Map的使用

1、什么是Map?

2、Map的常用方法

(1)V put(K key, V value)

(2)V get(Object key)

(3)V getOrDefault(Object key, V defaultValue)

(4)V remove(Object key)

(5)Set keySet()

(6)Collection values()

(7)Set> entrySet()

(8)boolean containsKey(Object key)

(9)boolean containsValue(Object value)

四、Set的使用 

1、什么是Set?

2、Set的常用方法

(1)boolean add(E e)

(2)void clear()

(3)boolean contains(Object o)

(4)Iterator iterator()

(5)boolean remove(Object o)

(6)int size()

(7)boolean isEmpty()

(8)Object[] toArray()

(9)boolean containsAll(Collection c)

(10)boolean addAll(Collection c)


在前面我们已经学完了数据结构中常见的排序算法,而今天我们就要开始学习数据结构上新的里程碑——Map & Set

一、搜索树

1、概念

二叉搜索树又称二叉排序树,它或者是一棵空树,并且这棵树具有以下这些性质:

  • 若它的左子树不为空,则左子树上所有节点的值都小于根节点的值
  • 若它的右子树不为空,则右子树上所有节点的值都大于根节点的值
  • 它的左右子树也分别为二叉搜索树

如下这棵树就是一棵二叉搜索树:

既然作为一棵树那么它也一定具有查找,插入和删除的功能,那么接下来就让我们来依次实现这些操作吧

由于是要我们自己来实现,那我们肯定要先做一下准备工作,我们要创建创建搜索树的结点和根结点

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 = null;
}

2、查找

这个操作就很简单了,我们只需要遍历这棵二叉搜索树判断是否有结点的val值与我们给的val值相等即可。

当然上述是对于一棵普通的二叉树的查找方式,而我们的二叉搜索树又称二叉排序树,那么它一定是有一定顺序的,所以查找方式也是有一定不同的根据上述的性质我们直到左子树的值都小于根节点的值,右子树的值多大于根节点的值,并且每棵子树也都是二叉搜索树。

1、我们可以先定义一个cur存储root,进行遍历


2、如果我们 cur的值小于我们要查找的值,就上我们的右子树上去找

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


3、如果我们 cur的值大于我们要查找的值,就上我们的左子树上去找

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


4、如果我们 cur的值等于于我们要查找的值,就返回cur

      cur.val == val 执行 return cur 


5、如果树为空或者没有要查找的值,就返回null

public TreeNode search(int val) {
        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;
    }

最优情况下,二叉搜索树为完全二叉树,其平均比较次数为: O(logN)

最差情况下,二叉搜索树退化为单支树,其平均比较次数为: N 

3、插入

1、我们要先判断是否为空树,如果为空树,那么我们此时要插入的结点就是我们的根结点


2、不为空树,我们就创建两个结点,prev和cur,cur用来遍历二叉搜索树,prev用来存储cur遍历到结点的根结点。


3、我们要先进行插入数据大小的判断如果大于cur.val,先让prev指向cur,然后让cur往右走,小于先让prev指向cur,然后让cur往左走。


4、如果我们在遍历的过程中发现我们要插入的值在二叉搜索树中存在,就直接返回不用插入。

5、如果cur指向null了,我们就代表可以进行插入了,跳出循环


6、跳出循环后,此时prev就是我们cur的父结点,我们要进行判断是在prev左边还右边进行插入

     如果prev的值小于val,在prev的右边进行插入

           prev.val < val 执行  prev.right =newTreeNode

     如果prev的值大于val,在prev的左边进行插入

            prev.val > val 执行  prev.left = newTreeNode


 public void insert(int val) {
        TreeNode newTreeNode =new TreeNode(val);
        if(root == null){
            root = newTreeNode;
          return;
        }
        TreeNode cur = root;
        TreeNode prev = null;
        while(cur != null){
            if(cur.val > val){
                prev = cur;
                cur = cur.right;
            }else if(cur.val < val){
                prev = cur;
                cur = cur.left;
            }else{
                return;
            }
        }

        if(prev.val < val){
            prev.right =newTreeNode;
        }
        if(prev.val > val){
            prev.left = newTreeNode;
        }
    }

4、删除

对于删除的操作,我们还是要先找到要删除的结点,我们还是利用cur和prev两个结点,cur用来查找要删除的结点,prev用来记录,我们遍历过程中cur的父节点,而当我们找到这个要删除的结点后,我们还要面临几种情况:


1、cur.left == null


2、cur.right==null


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

我们先创建两个结点 target 存储cur.right 和 targetParent 存储 cur,如果我们想要进行删除,我们必须要确保我们删除后,此时结点之后的左右子树依然能够是二叉搜索树,所以我们要确定我们新的值要比左边大,又要比右边小,而这时我们有两种删除方法:

 方法一:在左子树中找到左子树中的最大值(即左树的最右边的结点)

(因为左子树的最大值一定大于所有左子树的结点,并且因为最大值属于左树,左树的值是一定小于右树的,因此此时的最大值也一定是小于右树的),然后让他的值更新cur结点,最后我们只要删除这个结点即可

 方法二:在右子树中找到右子树中的最小值(即右数的最左边的结点)

(因为右子树的最小值一定小于所有右子树的结点,并且因为最小值属于右树,右树的值是一定大于左树的,因此此时的最小值也一定是大于左树的),然后让他的值更新cur结点,最后我们只要删除这个结点即可

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

    }

    public void removeNode(TreeNode cur ,TreeNode prev){
        if(cur.left == null){
            if(cur == root ){
                root = root.right;
            }else if(cur == prev.left){
               prev.left = cur.right;
            }else if(cur == prev.right){
                prev.right = cur.right;
            }
        }else if(cur.right == null){
            if(cur == root ){
                root = root.left;
            }else if(cur == prev.left){
                prev.left = cur.left;
            }else if(cur == prev.right){
                prev.right = cur.left;
            }
        }else{
            TreeNode target = cur.right;
            TreeNode targetParent = cur;
            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;
            }
        }
    }

二、搜索

1、概念及场景

Map和set是⼀种专门用来进行搜索的容器或者数据结构,其搜索的效率与其具体的实例化子类有关。 以前常见的搜索方式有:

1、直接遍历,时间复杂度为O(N),元素如果比较多效率会非常慢

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

上述查找方式比较适合进行静态查找的方式,我们在这种方式下一般不会进行插入和删除的操作,

因此这就要引出我们的动态查找方式,而这章要讲的Map和Set就是一种适合动态查找的集合容器

2、模型

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


(1)纯key模型

比如我们有一句英文:Failure is the fog through which we glimpse triumph.(透过失败的迷雾,才能瞥见胜利的光辉。

而我们的纯key模型,就是查找我们的单词 fog 是否出现在这句英文中。


(2)Key-Value模型

而我们的Key-Value模型,就是统计这句英文中每个单词出现的次数统计结果是每个单词都有与其对应的次数: <单词,单词出现的次数>

而接下来我们要介绍的Map中存储的就是key-value的键值对,Set中只存储了Key


三、Map的使用

1、什么是Map?

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

2、Map的常用方法

由于Map是是一个接口,不能自己进行实例化,我们需要使用TreeMap(红黑树)和HashMap(哈希桶)进行实例化。


(1)V put(K key, V value)

解释:设置 key 对应的 value

我们发现Map还会根据我们的key值自动排序 


(2)V get(Object key)

解释:返回 key 对应的 value


(3)V getOrDefault(Object key, V defaultValue)

解释:返回 key 对应的 value,key不存在,返回默认值


(4)V remove(Object key)

解释:删除 key 对应的映射关系


(5)Set<K> keySet()

解释:返回所有 key 的不重复集合


(6)Collection<V> values()

解释:返回所有 value 的可重复集合


(7)Set<Map.Entry<K,V>> entrySet()

解释:返回所有的 key-value 映射关系

在对他进行讲解前我们要先对Map.Entry<K,V>进行说明

Map.Entry是Map内部实现的用来存放键值对映射关系的内部类,该内部类中主要提供了的获取,value的设置以及Key的比较方式

方法解释
K getKey()返回 entry 中的 key
V getValue()返回 entry 中的 value
V setValue(V value)将键值对中的value替换为指定value


(8)boolean containsKey(Object key)

解释:判断是否包含 key


(9)boolean containsValue(Object value)

解释:判断是否包含 value


注意事项:

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

2、Map中存放键值对的Key是唯一的,value是可以重复的

3、在TreeMap中插入键值对时,key不能为空,否则就会抛NullPointerException异常,value可以为空。但是HashMap的key和value都可以为空。

4、Map中的Key可以全部分离出来,存储到Set中来进行访问(因为Key不能重复)。

5、Map中的value可以全部分离出来,存储在Collection的任何一个子集合中(value可能有重复)。

6、Map中键值对的Key不能直接修改,value可以修改,如果要修改key,只能先将该key删除掉,然 后再来进行重新插入。

四、Set的使用 

1、什么是Set?

Set与Map主要的不同有两点:Set是继承自Collection的接口类,Set中只存储了Key。

2、Set的常用方法

(1)boolean add(E e)

解释:添加元素,但重复元素不会被添加成功


(2)void clear()

解释:清空集合


(3)boolean contains(Object o)

解释:判断o是否在集合中


(4)Iterator<E> iterator()

解释:返回迭代器,通过迭代器进行打印


(5)boolean remove(Object o)

解释:删除集合中的 o


(6)int size()

解释:返回set中元素的个数


(7)boolean isEmpty()

解释:检测set是否为空,空返回true,否则返回false


(8)Object[] toArray()

解释:将set中的元素转换为数组返回


(9)boolean containsAll(Collection<?> c)

解释:集合c中的元素是否在set中全部存在,是返回true,否则返回false


(10)boolean addAll(Collection<?extends E> c)

解释:将集合c中的元素添加到set中,可以达到去重的效果


注意事项:

1、Set是继承自Collection的一个接口类

2、Set中只存储了key,并且要求key一定要唯一

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

4、Set最大的功能就是对集合中的元素进行去重

5、实现Set接口的常用类有TreeSet和HashSet,还有一个LinkedHashSet,LinkedHashSet是在 HashSet的基础上维护了一个双向链表来记录元素的插入次序。

6、Set中的Key不能修改,如果要修改,先将原来的删除掉,然后再重新插入

7、TreeSet中不能插入null的key,HashSet可以。


好了,今天的分享就到这里了还请大家多多关注,我们下一篇见! 

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

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

相关文章

关闭浏览器安全dns解决访问速度慢的问题

谷歌浏览器加载速度突然变慢了&#xff1f;检查安全DNS功能(DoH)是否被默认开启。 谷歌浏览器在去年已经推出安全DNS功能(即DoH) , 启用此功能后可以通过加密的DNS增强网络连接安全性。例如查询请求被加密后网络运营商将无法嗅探用户访问的地址&#xff0c;因此对于增强用户的…

C语言-章节 4:函数的定义与声明 ——「神秘法术的卷轴」

少年和 Inta 成功通过运算符与表达式的考验后&#xff0c;继续在函数城堡中探索。他们沿着一条闪烁着幽光的走廊前行&#xff0c;走廊两侧的墙壁上刻满了奇异的符号&#xff0c;仿佛在诉说着古老的编程秘密。终于&#xff0c;他们来到了一间神秘的房间&#xff0c;房间中央悬浮…

47.实验室管理系统(基于SSM和html的Java项目)

目录 1.系统的受众说明 2.系统可行性分析 2.1 经济可行性 2.2 技术可行性 2.2.1 Java Web技术 2.2.2 Eclipse 2.2.3 Tomcat 2.2.4 数据库 2.2.5 Layui框架 2.2.6 SSM框架 3.系统需求分析 3.1 用户需求分析 3.2 功能需求分析 3.3 其他需求分析 4.系统设计 4.1 系…

【免费送书活动】《MySQL 9从入门到性能优化(视频教学版)》

本博主免费赠送读者3本书&#xff0c;书名为《MySQL 9从入门到性能优化&#xff08;视频教学版&#xff09;》。 《MySQL 9从入门到性能优化&#xff08;视频教学版&#xff09;&#xff08;数据库技术丛书&#xff09;》(王英英)【摘要 书评 试读】- 京东图书 这本书已经公开…

【人工智能】通过python练习机器学习中的8大算法

python一系列练习在前面几节中基本练习了一遍&#xff0c;本篇通过机器学习的算法加强python的训练。我印象中常用的几种算法有&#xff1a;线性回归、逻辑回归&#xff0c;决策树&#xff0c;向量机SVM&#xff0c;KNN-近邻&#xff0c;朴素贝叶斯&#xff0c;K-means&#xf…

Android Studio2024版本安装环境SDK、Gradle配置

一、软件版本&#xff0c;安装包附上 &#x1f449;android-studio-2024.1.2.12-windows.exe&#x1f448; &#x1f449;百度网盘Android Studio安装包&#x1f448; &#xff08;若下载连链接失效可去百度网盘链接下载&#xff09; 二、软件安装过程 ​ ​ ​ 三、准备运行…

RabbitMQ学习—day2—安装

目录 普通Linux安装 安装RabbitMQ 1、下载 2、安装 3. Web管理界面及授权操作 Docker 安装 强力推荐学docker&#xff0c;使用docker安装 普通Linux安装 安装RabbitMQ 1、下载 官网下载地址&#xff1a;https://www.rabbitmq.com/download.html(opens new window) 这…

Jenkins 新建配置Pipeline任务 三

Jenkins 新建配置Pipeline任务 三 一. 登录 Jenkins 网页输入 http://localhost:8080 输入账号、密码登录 一个没有创建任务的空 Jenkins 二. 创建 任务 图 NewItem 界面左上角 New Item 图NewItemSelect 1.Enter an item name&#xff1a;输入任务名 2.Select an ite…

社区版IDEA中配置TomCat(详细版)

文章目录 1、下载Smart TomCat2、配置TomCat3、运行代码 1、下载Smart TomCat 由于小编的是社区版&#xff0c;没有自带的tomcat server&#xff0c;所以在设置的插件里面搜索&#xff0c;安装第一个&#xff08;注意&#xff1a;安装时一定要关闭外网&#xff0c;小编因为这个…

MATLAB 生成脉冲序列 pulstran函数使用详解

MATLAB 生成脉冲序列 pulstran函数使用详解 目录 前言 一、参数说明 二、示例一 三、示例二 总结 前言 MATLAB中的pulstran函数用于生成脉冲序列&#xff0c;支持连续或离散脉冲。该函数通过将原型脉冲延迟并相加&#xff0c;生成脉冲序列&#xff0c;适用于信号处理和系统…

概率论、组合数学知识点汇总

1、概率论知识点 全概率公式&#xff1a;如果事件B1,B2,…,Bn是样本空间的一个划分&#xff0c;则&#xff1a;贝叶斯定理&#xff1a;协方差&#xff1a;协方差用来衡量两个变量之间的变化趋势是否一致&#xff0c;公式为相关系数&#xff08;Pearson&#xff09;&#xff1a…

【人工智能】deepseek R1模型在蓝耘智算平台的搭建与机器学习的探索

&#x1f4dd;个人主页&#x1f339;&#xff1a;Eternity._ &#x1f339;&#x1f339;期待您的关注 &#x1f339;&#x1f339; ❀ 蓝耘智算平台 deepseek R1简介与优点蓝耘智算平台蓝耘智算平台简介蓝耘智算平台优势deepseek R1模型在蓝耘智算平台的搭建模型使用与机器学习…

tomcat html乱码

web tomcat html中文乱码 将html文件改成jsp <% page language"java" contentType"text/html; charsetUTF-8" pageEncoding"UTF-8"%>添加 <meta charset"UTF-8">

基于单片机的智能奶茶机(论文+源码+图纸)

1总体架构设计 本课题为基于单片机的智能奶茶机设计&#xff0c;其系统架构上设计如图2.1所示&#xff0c;整个系统包括了DS18B20温度传感器、继电器模块、LCD液晶、蜂鸣器、按键、STC89C52单片机等器件&#xff0c;在功能上用户可以通过按键键控制选择甜度和添加物以及设置温度…

Centos7系统安装redis

Centos7系统安装redis 下载编译配置配置环境变量服务脚本安装使用远程连接 下载 下载地址&#xff1a;https://download.redis.io/releases/&#xff0c;选择版本6.2.7 具体下载链接&#xff1a;https://download.redis.io/releases/redis-6.2.7.tar.gz 操作&#xff1a;在ro…

图数据库neo4j进阶(一):csv文件导入节点及关系

CSV 一、load csv二、neo4j-admin import<一>、导入入口<二>、文件准备<三>、命令详解 一、load csv 在neo4j Browser中使用Cypher语句LOAD CSV,对于数据量比较大的情况,建议先运行create constraint语句来生成约束 create constraint for (s:Student) req…

深度剖析责任链模式

一、责任链模式的本质&#xff1a;灵活可扩展的流水线处理 责任链模式&#xff08;Chain of Responsibility Pattern&#xff09;是行为型设计模式的代表&#xff0c;其核心思想是将请求的发送者与接收者解耦&#xff0c;允许多个对象都有机会处理请求。这种模式完美解决了以下…

floodfill算法系列一>岛屿的最大面积

题解 整体思路&#xff1a;代码设计&#xff1a;代码呈现&#xff1a; 整体思路&#xff1a; 代码设计&#xff1a; 代码呈现&#xff1a; class Solution {int ret,m,n,count;boolean[][] vis;public int maxAreaOfIsland(int[][] grid) {m grid.length;n grid[0].length;v…

手机用流量怎样设置代理ip?

互联网各领域资料分享专区(不定期更新)&#xff1a; Sheet

游戏引擎学习第100天

仓库:https://gitee.com/mrxiao_com/2d_game_2 昨天的回顾 今天的工作重点是继续进行反射计算的实现。昨天&#xff0c;我们开始了反射和环境贴图的工作&#xff0c;成功地根据法线显示了反射效果。然而&#xff0c;我们还没有实现反射向量的计算&#xff0c;导致反射交点的代…