【Map和Set】

目录

1,搜索树

1.1 概念

1.2 查找 

1.3 插入

1.4 删除(难点)

1.5 性能分析

1.6 和 java 类集的关系

2,搜索

2.1 概念及场景

2.2 模型

3,Map 的使用

3.1 关于Map的说明

3.2 关于Map.Entry的说明

3.3 Map的常用方法说明

4,Set 的说明

4.1 常见方法说明

5,哈希表

5.1 概念

5.2 冲突-概念

5.3 冲突-避免

5.4 冲突-避免-哈希函数设计

5.5 冲突-避免-负载因子调节(重点掌握)

5.6 冲突-解决

5.7 冲突-解决-闭散列

5.8 冲突-解决-开散列/哈希桶(重点掌握)

5.9 冲突严重时的解决办法

5.10 实现

5.11 使用泛型实现(传入指定类型)

5.12 性能分析

5.12 和 java 类集的关系

6,OJ练习

6.1 只出现一次的数字

6.2 随机链表的复制 (百度面试)

6.3 宝石与石头

6.4 坏键盘打字

6.5 前K个高频单词


1,搜索树

1.1 概念

二叉搜索树又称二叉排序树,它或者是一棵空树,或者是具有以下性质的二叉树

若它的左子树不为空,则左子树上所有节点的值都小于根节点的值

若它的右子树不为空,则右子树上所有节点的值都大于根节点的值

它的左右子树也分别为二叉搜索树

为什么又称二叉排序树呢,因为对棵树进行中序遍历,其最终的结果是有序的

1.2 查找 

虽然还没有实现一颗二叉搜索树,但是不影响我们写查找。

若没找到可进行异常处理,此代码没找到会出现空指针异常 

1.3 插入

1.4 删除(难点)

1.5 性能分析

插入和删除操作都必须先查找,查找效率代表了二叉搜索树中各个操作的性能。

对有n个结点的二叉搜索树,若每个元素查找的概率相等,则二叉搜索树平均查找长度是结点在二叉搜索树的深度的函数,即结点越深,则比较次数越多。

1.6 和 java 类集的关系

TreeMap 和 TreeSet 即 java 中利用搜索树实现的 Map 和 Set;实际上用的是红黑树,而红黑树是一棵近似平衡的二叉搜索树,即在二叉搜索树的基础之上 + 颜色以及红黑树性质验证,关于红黑树的内容后序再进行讲解。

2,搜索

2.1 概念及场景

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

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

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

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

1. 根据姓名查询考试成绩

2. 通讯录,即根据姓名查询联系方式

3. 不重复集合,即需要先搜索关键字是否已经在集合中

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

2.2 模型

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

1. 纯 key 模型(TreeSet),比如:

有一个英文词典,快速查找一个单词是否在词典中

快速查找某个名字在不在通讯录中

2. Key-Value 模型(TreeMap),比如:

统计文件中每个单词出现的次数,统计结果是每个单词都有与其对应的次数:<单词,单词出现的次数>

梁山好汉的江湖绰号:每个好汉都有自己的江湖绰号

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

3,Map 的使用

3.1 关于Map的说明

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

3.2 关于Map.Entry的说明

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

3.3 Map的常用方法说明

1. put(K key,V value)

2. get(Object key)   通过key获取val

如果获取key没有对应的val,返回null

3. getOrDefault(object K,V DefaultValue)    如果获取key没有对应的val,给一个默认值

4. remove(Obejct key)   删除key对应的val

5,keySet()     将所有不重复的key放到Set集合

结论:当你在map当中存储元素的时候,key是不能有重复的,如果key重复了将会更新val值

6. entrySet()    返回所有key,value

注意:

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

2. Map中存放键值对的Key是唯一的,value是可以重复的(就是根据key确定当前元素的位置,不能重复)

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

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

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

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

7. TreeMap和HashMap的区别【HashMap在课件最后会讲到】

8. 往TreeMap里面存储元素时,当前这个key值一定是可比较的,否则会报类型转换异常。

4,Set 的说明

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

4.1 常见方法说明

1. add()   Set当中不能存储重复的元素

2. iterator()   使用迭代器打印

......这些方法可以自己使用使用

我们来查看TreeSet的源码:

再来查看add的源码:

注意:

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可以。

8. TreeSet和HashSet的区别【HashSet在课件最后会讲到】

5,哈希表

5.1 概念

顺序结构以及平衡树中,元素关键码与其存储位置之间没有对应的关系,因此在查找一个元素时,必须要经过关键码的多次比较。顺序查找时间复杂度为O(N),平衡树中为树的高度,即O(log2为底的N ),搜索的效率取决于搜索过程中元素的比较次数。

理想的搜索方法:可以不经过任何比较,一次直接从表中得到要搜索的元素。 如果构造一种存储结构,通过某种函数(hashFunc)使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快 找到该元素。

当向该结构中:

插入元素:根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放

搜索元素:对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若关键码相等,则搜索成功

该方式即为哈希(散列)方法,哈希方法中使用的转换函数称为哈希(散列)函数,构造出来的结构称为哈希表(Hash Table)(或者称散列表)

例如:数据集合{1,7,6,4,5,9};

哈希函数设置为:hash(key) = key % capacity; capacity为存储元素底层空间总的大小。

用该方法进行搜索不必进行多次关键码的比较,因此搜索的速度比较快

问题:按照上述哈希方式,向集合中插入元素14,会出现什么问题?

5.2 冲突-概念

对于两个数据元素的关键字,即:不同关键字通过相同哈希哈数计算出相同的哈希地址,该种现象称为哈希冲突或哈希碰撞。

把具有不同关键码而具有相同哈希地址的数据元素称为“同义词”。

5.3 冲突-避免

首先,我们需要明确一点,由于我们哈希表底层数组的容量往往是小于实际要存储的关键字的数量的,这就导致一个问题,冲突的发生是必然的,但我们能做的应该是尽量的降低冲突率

比如我的数组容量是10,有可能我存储的关键字有12个(这是可以存下来的,下面讲到)。

比如容量为10,存两个元素,这两个元素都可能在同一位置,所以冲突是必然的,只能避免冲突

5.4 冲突-避免-哈希函数设计

设计合理的hash函数:

哈希函数的定义域必须包括需要存储的全部关键码,而如果散列表允许有m个地址时,其值域必须在0到m-1 之间

哈希函数计算出来的地址能均匀分布在整个空间中

哈希函数应该比较简单

常见哈希函数:

1. 直接定制法--(常用)

取关键字的某个线性函数为散列地址:Hash(Key)= A*Key + B 优点:简单、均匀 缺点:需要事先知道关键字的分布情况使用场景:适合查找比较小且连续的情况

面试题:给定一个字符串 s ,找到它的第一个不重复的字符,并返回它的索引 。如果不存在,则返回 -1 。

2. 除留余数法--(常用)

设散列表中允许的地址数为m,取一个不大于m,但最接近或者等于m的质数p作为除数,按照哈希函数: Hash(key) = key% p(p<=m),将关键码转换成哈希地址

5.5 冲突-避免-负载因子调节(重点掌握)

较低的负载因子:

所以当冲突率达到一个无法忍受的程度时,我们需要通过降低负载因子来变相的降低冲突率。

已知哈希表中已有的关键字个数是不可变的,那我们能调整的就只有哈希表中的数组的大小。

5.6 冲突-解决

解决哈希冲突两种常见的方法是:闭散列和开散列

5.7 冲突-解决-闭散列

闭散列:也叫开放地址法,当发生哈希冲突时,如果哈希表未被装满,说明在哈希表中必然还有空位置,那么可以把key存放到冲突位置中的“下一个” 空位置中去。那如何寻找下一个空位置呢?

1. 线性探测

比如上面的场景,现在需要插入元素44,先通过哈希函数计算哈希地址,下标为4,因此44理论上应该插在该位置,但是该位置已经放了值为4的元素,即发生哈希冲突。

线性探测:从发生冲突的位置开始,依次向后探测,直到寻找到下一个空位置为止。

采用闭散列处理哈希冲突时,不能随便物理删除哈希表中已有的元素,若直接删除元素会影响其他 元素的搜索。比如删除元素4,如果直接删除掉,44查找起来可能会受影响。因此线性探测采用标 记的伪删除法来删除一个元素。        

2. 二次探测

线性探测的缺陷是产生冲突的数据堆积在一块,这与其找下一个空位置有关系,因为找空位置的方式就是挨着往后逐个去找,因此二次探测为了避免该问题,找下一个空位置的方法为:,或者:Hi。其中:i = 1,2,3…, H0是通过散列函数Hash(x)对元素的关键码 key 进行计算得到的位置, m是表的大小。

研究表明:当表的长度为质数且表装载因子a不超过0.5时,新的表项一定能够插入,而且任何一个位置都不会被探查两次。因此只要表中有一半的空位置,就不会存在表满的问题。在搜索时可以不考虑表装满的情况,但在插入时必须确保表的装载因子a不超过0.5,如果超出必须考虑增容。

因此:比散列最大的缺陷就是空间利用率比较低,这也是哈希的缺陷。

5.8 冲突-解决-开散列/哈希桶(重点掌握)

java当中的HashMap也是以这样的方式来解决问题的

开散列法又叫链地址法(开链法),首先对关键码集合用散列函数计算散列地址,具有相同地址的关键码归于同一子集合,每一个子集合称为一个桶,各个桶中的元素通过一个单链表链接起来,各链表的头结点存储在哈希表中。

从上图可以看出,开散列中每个桶中放的都是发生哈希冲突的元素。

开散列,可以认为是把一个在大集合中的搜索问题转化为在小集合中做搜索了。

5.9 冲突严重时的解决办法

刚才我们提到了,哈希桶其实可以看作将大集合的搜索问题转化为小集合的搜索问题了,那如果冲突严重,就意味着小集合的搜索性能其实也时不佳的,这个时候我们就可以将这个所谓的小集合搜索问题继续进行转化,例如:

1. 每个桶的背后是另一个哈希表

2. 每个桶的背后是一棵搜索树

5.10 实现

实现的是一个简单哈希桶。

首先是一个数组,数组里面放的是头节点的地址

 1. put()

2. get(int key)  通过key获取val

5.11 使用泛型实现(传入指定类型)

首先我们写一个学生类,我们认为学号一样就是同一个学生,但是呢实际上是不一样的

刚刚上面的代码,如果我们的key不是整型,而是一个引用类型,比如是一个Student,此时代码就执行不了,我们需要把一个引用对象转变为整数,我们可以通过hashcode方法来转变,上面我们认为同一个学号就是同一个学生,那么得到的hashcode整数也应该是一样的,即通过key去%数组长度得到的index位置也是一样的,也就会哈希到同一位置

但是当我运行的时候,得到的这两个整数并不一样,意味着说虽然学号一样,还是不认为你是同一个学生

那么在我们的HashMap来说,要获取key来%数组长度,你的对象肯定做不到,我们期望通过hashcode得到的这两个整数应该是同一个整数,但是不是,那我们起码还是要根据对象的学号生成这个整数,这时候我们需要重写equals和hashcode,重写equals返回true,false证明他是不是同一个人,重写hashcode返回是整数,如果返回的整数是一样的情况下,得到index的值就是一样的

当我们重写这两个方法以后,运行时这两个hashcode值就一样了,所以说我们以后自定义的类型,一定要重写hashcode和equals方法,甚至于说这个类还要实现Comparable接口,让他可比较

这个时候我们就知道了生成的hashcode值是一样的,将来我们key去%数组长度时就好实现了

所以,解决了这个问题,我们就可以使用泛型来实现了!!!

5.12 性能分析

虽然哈希表一直在和冲突做斗争,但在实际使用过程中,我们认为哈希表的冲突率是不高的,冲突个数是可控的, 也就是每个桶中的链表的长度是一个常数,所以,通常意义下,我们认为哈希表的插入/删除/查找时间复杂度是 O(1) 。

5.12 和 java 类集的关系

1. HashMap 和 HashSet 即 java 中利用哈希表实现的 Map 和 Set

2. java 中使用的是哈希桶方式解决冲突的

3. java 会在冲突链表长度大于一定阈值后,将链表转变为搜索树(红黑树)

4. java 中计算哈希值实际上是调用的类的 hashCode 方法,进行 key 的相等性比较是调用 key 的 equals 方法。所以如果要用自定义类作为 HashMap 的 key 或者 HashSet 的值,必须覆写 hashCode 和 equals 方法,而且要做到 equals 相等的对象,hashCode 一定是一致的。

所以HashSet的底层也是HashMap

6,OJ练习

6.1 只出现一次的数字

给你一个 非空 整数数组 nums ,除了某个元素只出现一次以外,其余每个元素均出现两次。找出那个只出现了一次的元素。

你必须设计并实现线性时间复杂度的算法来解决此问题,且该算法只使用常量额外空间。

但是对于此代码来说,还是使用异或时间快

6.2 随机链表的复制 (百度面试)

注意:这里不能使用TreeMap,因为他是一颗二叉搜索树,map.put的时候会根据key进行比较,这里没有说你的Node根据什么比较,且没有实现Comparable,所以在用TreeMap的时候,要看看你的key能不能进行比较,不能比较使用HashMap较好!!!

6.3 宝石与石头

6.4 坏键盘打字

旧键盘上坏了几个键,于是在敲一段文字的时候,对应的字符就不会出现。现在给出应该输入的一段文字、以及实际被输入的文字,请你列出肯定坏掉的那些键。

练习:为6.5做准备

6.5 前K个高频单词

代码:

此时的代码有一点问题:

我们确实是处理过,但是我们处理的是放满k个的时候,那没有放满k个呢?

所以,我们又要讨论一下!!!

代码:

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JAVA-----异常处理

一、定义 在 Java 中&#xff0c;异常&#xff08;Exception&#xff09;是指程序在执行过程中遇到的不正常情况&#xff0c;这些情况可能导致程序无法继续执行或产生错误的结果。异常可以是 Java 标准库中提供的内置异常类&#xff0c;也可以是开发人员自定义的异常类。 二、…

小程序-2(WXML数据模板+WXSS模板样式+网络数据请求)

目录 1.WXML数据模板 数据绑定 事件绑定 小程序中常用的事件 事件对象的属性列表 target和currentTarget的区别 bindtap的语法格式 在事件处理事件中为data中的数据赋值 事件传参与数据同步 事件传参 bindinput的语法绑定事件 文本框和data的数据同步 条件渲染 w…

Spring Data Redis + Redis数据缓存学习笔记

文章目录 1 Redis 入门1.1 简介1.2 Redis服务启动与停止&#xff08;Windows&#xff09;1.2.1 服务启动命令1.2.2 客户端连接命令1.2.3 修改Redis配置文件1.2.4 Redis客户端图形工具 2. Redis数据类型2.1 五种常用数据类型介绍 3. Redis常用命令3.1 字符串操作命令3.2 哈希操作…

数据库的约束条件和用户管理

约束条件&#xff1a; 主键&#xff1a;主键约束 primary key 用于标识表中的主键列的值&#xff0c;而且这个值是全表当中唯一的&#xff0c;而且只不能为null 一个表只能有一个主键。 外键&#xff1a;用来建立表与表之间的关系。确保外键中的值于另一个表的主键值匹配&a…

golang AST语法树解析

1. 源码示例 package mainimport ("context" )// Foo 结构体 type Foo struct {i int }// Bar 接口 type Bar interface {Do(ctx context.Context) error }// main方法 func main() {a : 1 }2. Golang中的AST golang官方提供的几个包&#xff0c;可以帮助我们进行A…

集线器、交换机、路由器的区别,冲突域、广播域

冲突域 定义&#xff1a;同一时间内只能有一台设备发送信息的范围。 分层&#xff1a;基于OSI模型的第一层物理层。 广播域 定义&#xff1a;如果某个站点发出一个广播信号&#xff0c;所有能接受到这个信号的设备的范围称为一个广播域。 分层&#xff1a;基于OSI模型的第二…

为ppt中的文字配色

文字的颜色来源于ppt不可删去的图像的颜色 从各类搜索网站中搜索ppt如何配色&#xff0c;有如下几点&#xff1a; 1.可以使用对比色&#xff0c;表示强调。 2.可以使用近似色&#xff0c;使得和谐统一。 3.最好一张ppt中&#xff0c;使用的颜色不超过三种主要颜色。 但我想强调…

第二证券:电影暑期档持续升温 农机自动驾驶驶入快车道

农机自动驾驶打开驶入快车道 得益于农机补贴、土地流通、高标准农田制造等方针引导&#xff0c;叠加技术突围和用户降本增效的内生需求&#xff0c;我国正处于农业2.0向农业3.0的过渡阶段。其间农机自动驾驶系统是结束农业3.0&#xff08;即自动化&#xff09;的要害并迎来快速…

【瑞吉外卖 | day07】移动端菜品展示、购物车、下单

文章目录 瑞吉外卖 — day71. 导入用户地址簿相关功能代码1.1 需求分析1.2 数据模型1.3 代码开发 2. 菜品展示2.1 需求分析2.2 代码开发 3. 购物车3.1 需求分析3.2 数据模型3.3 代码开发 4. 下单4.1 需求分析4.2 数据模型4.3 代码开发 瑞吉外卖 — day7 移动端相关业务功能 —…

Java实验4

实验内容 考试题 要求在一个界面内至少显示5道选择题&#xff0c;每道题4个选项。题目从数据库读取。表结构自定义。 另有2个命令按钮&#xff0c;分别为“重新答题”&#xff08;全部选项及正确答题数清空&#xff09;和“提交”&#xff08;计算&#xff09;&#xff0c;在…

【芯片设计- RTL 数字逻辑设计入门 9.1 -- CRG模块】

请阅读【芯片设计 RTL 数字逻辑设计扫盲 】 转自&#xff1a;芯片设计基础 – CRG模块 文章目录 CRG模块CRG时钟系统CRG复位系统同步复位同步复位的优点同步复位的缺点 异步复位异步复位的优点异步复位的缺点 异步复位同步释放 CRG模块 CRG是芯片里的时钟和复位生成模块&#…

27.js实现鼠标拖拽

e.offsetX是鼠标距离准确事件源的左上角距离 e.clientX是鼠标距离浏览器可视窗口左上角的距离 e.pageX是鼠标距离文档左上角的距离 /* 当鼠标点击div时开始挪动&#xff0c;当鼠标抬起&#xff0c;div静止——事件源是div 当鼠标点击后,鼠标在移动——事件源…

Web开发:卡片翻转效果(HTML、CSS)

目录 一、实现效果 二、完整代码 三、实现过程 1、页面结构 2、初始样式 3、翻转效果 4、图片大小问题 一、实现效果 如下图所示&#xff0c;当鼠标移入某个盒子&#xff0c;就反转这个盒子&#xff0c;并显示其背面的内容——卡片翻转效果&#xff1b; 卡片翻转效果 二…

【STM32 IDE】使用STM32CubeIDE创建一个工程

关于IDE的下载安装和环境配置这里暂且不介绍&#xff0c;我们直接使用STM32F407ZGT6创建工程。 这里需要注意两点&#xff1a; 创建工程时&#xff0c;默认使用最新版本的固件包&#xff08;HAL库&#xff09;&#xff0c;好像还不让更改。如果本地电脑位置没有该版本的包&…

webpack优化

优化方向 热更新 概念 /** hmr: hot module replacement 热模块替换 / 模块热更新作用&#xff1a; 一个模块发生改变&#xff0c;只会重新打包这一个模块&#xff08;而不是打包所有模块&#xff09;&#xff0c;极大的提升了构建速度样式文件&#xff1a; 可以使用hmr功能…

防火墙-NAT策略和智能选路

一、背景技术 在日常网络环境&#xff0c;内部网络想要访问外网无法直接进行通信&#xff0c;这时候就需要进行NAT地址转换&#xff0c;而在防火墙上配置NAT和路由器上有点小区别&#xff0c;思路基本一致&#xff0c;这次主要就以防火防火墙配置NAT策略为例&#xff0c;防火墙…

【学习css3】使用flex和grid实现等高元素布局

过往的实现方法是使用浮动加计算布局来实现&#xff0c;当flex和grid问世时&#xff0c;这一切将变得简单起来 一、简单的两列实现 1、先看页面效果 2、css代码 .container {padding: 10px;width: 100ch;margin: 0 auto;box-shadow: inset 0 0 0 2px #ccc;}.column {margin: 2…

git clone 报错 Unable to negotiate

Unable to negotiate with 192.168.110.10 port 39418: no matching cipher found. Their offer: aes128-cbc,3des-cbc,blowfish-cbc,aes192-cbc,aes256-cbc fatal: Could not read from remote repository. 查询支持哪些加密算法 ssh -Q cipher 修改文件 /etc/ssh/ssh_config…

AR0132AT 1/3 英寸 CMOS 数字图像传感器(AR0132AT6R、AR0132AT6C)适用于监控和高清视频等多种应用

AR0132AT 1/3 英寸 CMOS 数字图像传感器&#xff0c;带 1280H x 960V 有效像素阵列。它能在线性或高动态模式下捕捉图像&#xff0c;且带有卷帘快门读取。它包含了多种复杂的摄像功能&#xff0c;如自动曝光控制、开窗&#xff0c;以及视频和单帧模式。它适用于低光度和高动态范…

基于AT89C51单片机构造波形发生器设计(含文档、源码与proteus仿真,以及系统详细介绍)

本篇文章论述的是基于AT89C51单片机构造波形发生器设计的详情介绍&#xff0c;如果对您有帮助的话&#xff0c;还请关注一下哦&#xff0c;如果有资源方面的需要可以联系我。 目录 摘要 仿真图 总体结构框图 仿真程序效果图 原理图 代码 系统论文&#xff08;部分&…