【数据结构】Map的使用与注意事项

简介: 【数据结构】Map的使用与注意事项

概念

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

  1. 直接遍历,时间复杂度为 O ( N ) ,元素如果比较多效率会非常慢
  2. 二分查找,时间复杂度为 O ( l o g N ),但搜索前必须要求序列是有序的

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

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

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

模型

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

  1. key模型,比如:
  • 有一个英文词典,快速查找一个单词是否在词典中
  • 快速查找某个名字在不在通讯录中
  1. Key-Value模型,比如:
  • 统计文件中每个单词出现的次数,统计结果是每个单词都有与其对应的次数:<单词,单词出现的次数>
  • 梁山好汉的江湖绰号:每个好汉都有自己的江湖绰号

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

Map 的使用

MapSet 主要用于搜索

  • TreeSetTreeMap 底层就是一颗二叉搜索树==>红黑树
方法 解释
V get(Object key) 返回 key 对应的 value
V getOrDefault(Object key, V defaultValue) 返回 key 对应的 value,key 不存在,返回默认值
V put(K key, V value) 设置 key 对应的 value
V remove(Object key) 删除 key 对应的映射关系
Set keySet() 返回所有 key 的不重复集合
Collection values() 返回所有 value 的可重复集合
Set> entrySet() 返回所有的 key-value 映射关系
boolean containsKey(Object key) 判断是否包含 key
boolean containsValue(Object value) 判断是否包含 value

put() 和 get()

Map<String,String> map = new TreeMap<>();  
map.put("及时雨","松江");  
map.put("齐天大圣","孙悟空");  
  
String val = map.get("齐天大圣");  
String val2 = map.get("孙悟空");  
System.out.println(val);  
System.out.println(val2);
/*
运行结果:
孙悟空
null
*/
  • put 的时候是有顺序的,前面的是 Key ,后面的是 Value
  • 进行 get 的时候是返回 Key 所对应的 Value,而不能返回 Value 所对应的 Key

getOrDefault()

当没有找到 Key 所对应的 Value 值时,会默认输出 null,但默认值可以改

Map<String,String> map = new TreeMap<>();  
map.put("及时雨","松江");  
map.put("齐天大圣","孙悟空");  
  
String val3 = map.getOrDefault("弼马温","没找到啊");  
System.out.println(val3);
/*
运行结果:
没找到啊
*/
  • 如果没有“弼马温”这个 Key,就取不到 Value,就给一个默认值“没找到啊

remove()

就是删除的意思,删除 Key 对应的映射关系

Map<String,String> map = new TreeMap<>();  
map.put("及时雨","松江");  
map.put("齐天大圣","孙悟空");  
String val3 = map.remove("齐天大圣");  
System.out.println(val3);
String val4 = map.get("齐天大圣");
System.out.println(val4);
/*
运行结果:
孙悟空
null
*/
  • 因为这个方法的返回值是 Value,所以还是会打印出“孙悟空”,但之后 Key(齐天大圣)和 Value(孙悟空)之间的映射关系就被删除了,不存在了
  • 所以第二次再 get 这个 KeyValue 值就找不到了

keySet()

将所有的 Key 都拿出来,放在一个 Set 集合中

Map<String,String> map = new TreeMap<>();  
map.put("及时雨","松江");  
map.put("齐天大圣","孙悟空");    
map.put("齐天大圣","弼马温");
  
Set<String> set = map.keySet();  
System.out.println(set);
System.out.println(map.get("齐天大圣"));
/*
运行结果:
[及时雨, 齐天大圣]
弼马温
*/
  • 因为 Key 都是 String,所以用一个 String 类型的 Set 进行接收
  • Key 是不能重复的,如果重复了,就会更新 Key 的值

entrySet()

如果想将 KeyValue 的映射关系一起返回,就可以调用 entrySet

Map<String,String> map = new TreeMap<>();  
map.put("及时雨","松江");  
map.put("齐天大圣","孙悟空");  
  
Set<Map.Entry<String,String>> entries = map.entrySet();  
System.out.println(entries);
System.out.println(===============);
for (Map.Entry<String,String> entry : entries){  
    System.out.println(entry);  
}
System.out.println(===============);
for (Map.Entry<String,String> entry : entries){  
    System.out.println("Key:"+entry.getKey()+" Value:"+entry.getValue());  
}
/*
运行结果:
[及时雨=松江, 齐天大圣=孙悟空]
===============
及时雨=松江
齐天大圣=孙悟空
===============
Key:及时雨 Value:松江
Key:齐天大圣 Value:孙悟空
*/
  • Entry 里面也可以单独的取出 Key 或者 Value
  • EntryMap接口的内置接口,其内部有
  • getKey 方法,用来获取 Key
  • getValue 方法,用来获取 Value
  • setValue 方法,用来更新 Value

注意事项

  1. Map 是一个接口,不能直接实例化对象,如果要实例化对象只能实例化其实现类 TreeMap 或者 HashMap (搜索树,红黑树)
  2. Map 中存放键值对的 Key 是唯一的,value 是可以重复的
  3. TreeMap 中插入键值对时,key 不能为空,否则就会抛 NullPointerException 异常,value 可以为空。但是 HashMapkeyvalue 都可以为空。
  4. Map 中的 Key 可以全部分离出来,存储到 Set 中来进行访问(因为 Key 不能重复)。
  5. Map 中的 value 可以全部分离出来,存储在 Collection 的任何一个子集合中(value 可能有重复)。
  6. Map 中键值对的 Key 不能直接修改,value 可以修改,如果要修改 key,只能先将该 key 删除掉,然后再来进行重新插入。
  7. TreeMap 中存储元素的时候,Key 一定是要可以比较的,因为 Key 的底层是红黑树,要将 Key 按大小顺序排列好。如果你传入一个类的时候,就要注意了
Map 底层结构 TreeMap HashMap
底层结构 红黑树 哈希桶
插入/删除/查找时间复杂度 O ( l o g N ) O(logN) O(logN) O ( 1 ) O(1) O(1)
是否有序 关于Key有序 无序
线程安全 不安全 不安全
插入/删除/查找区别 需要进行元素比较 通过哈希函数计算哈希地址
比较与覆写 key必须能够比较,否则会抛出

ClassCastException异常
自定义类型需要覆写equals和

hashCode方法
应用场景 需要Key有序场景下 Key是否有序不关心,需要更高的 时间性能


相关文章
|
8天前
|
存储 JavaScript 前端开发
for...of循环在遍历Set和Map时的注意事项有哪些?
for...of循环在遍历Set和Map时的注意事项有哪些?
32 0
|
8天前
|
存储 编译器 容器
set、map、multiset、multimap的介绍及使用以及区别,注意事项
set是按照一定次序存储元素的容器,使用set的迭代器遍历set中的元素,可以得到有序序列。set当中存储元素的value都是唯一的,不可以重复,因此可以使用set进行去重。set默认是升序的,但是其内部默认不是按照大于比较,而是按照小于比较。set中的元素不能被修改,因为set在底层是用二叉搜索树来实现的,若是对二叉搜索树当中某个结点的值进行了修改,那么这棵树将不再是二叉搜索树。
|
8月前
|
存储 Java
告别混乱!用Java Map优雅管理你的数据结构
【10月更文挑战第17天】在软件开发中,随着项目复杂度增加,数据结构的组织和管理至关重要。Java中的Map接口提供了一种优雅的解决方案,帮助我们高效、清晰地管理数据。本文通过在线购物平台的案例,展示了Map在商品管理、用户管理和订单管理中的具体应用,有效提升了代码质量和维护性。
161 2
|
8月前
|
存储 Java 开发者
Java Map实战:用HashMap和TreeMap轻松解决复杂数据结构问题!
【10月更文挑战第17天】本文深入探讨了Java中HashMap和TreeMap两种Map类型的特性和应用场景。HashMap基于哈希表实现,支持高效的数据操作且允许键值为null;TreeMap基于红黑树实现,支持自然排序或自定义排序,确保元素有序。文章通过具体示例展示了两者的实战应用,帮助开发者根据实际需求选择合适的数据结构,提高开发效率。
195 2
|
5月前
|
存储 安全 Go
Go语言中的map数据结构是如何实现的?
Go 语言中的 `map` 是基于哈希表实现的键值对数据结构,支持快速查找、插入和删除操作。其原理涉及哈希函数、桶(Bucket)、动态扩容和哈希冲突处理等关键机制,平均时间复杂度为 O(1)。为了确保线程安全,Go 提供了 `sync.Map` 类型,通过分段锁实现并发访问的安全性。示例代码展示了如何使用自定义结构体和切片模拟 `map` 功能,以及如何使用 `sync.Map` 进行线程安全的操作。
113 9
|
8月前
|
存储 Java 开发者
Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效
【10月更文挑战第19天】在软件开发中,随着项目复杂度的增加,数据结构的组织和管理变得至关重要。Java中的Map接口提供了一种优雅的方式来管理数据结构,使代码更加清晰、高效。本文通过在线购物平台的案例,展示了Map在商品管理、用户管理和订单管理中的具体应用,帮助开发者告别混乱,提升代码质量。
76 1
|
9月前
|
存储 Java API
【数据结构】map&set详解
本文详细介绍了Java集合框架中的Set系列和Map系列集合。Set系列包括HashSet(哈希表实现,无序且元素唯一)、LinkedHashSet(保持插入顺序的HashSet)、TreeSet(红黑树实现,自动排序)。Map系列为双列集合,键值一一对应,键不可重复,值可重复。文章还介绍了HashMap、LinkedHashMap、TreeMap的具体实现与应用场景,并提供了面试题示例,如随机链表复制、宝石与石头、前K个高频单词等问题的解决方案。
117 6
【数据结构】map&set详解
|
8月前
|
存储 缓存 Java
【用Java学习数据结构系列】HashMap与TreeMap的区别,以及Map与Set的关系
【用Java学习数据结构系列】HashMap与TreeMap的区别,以及Map与Set的关系
111 1
|
8月前
|
存储 安全
【数据结构】Set的使用与注意事项
【数据结构】Set的使用与注意事项
93 2
|
11月前
|
存储 算法 C++
【C++高阶】探索STL的瑰宝 map与set:高效数据结构的奥秘与技巧
【C++高阶】探索STL的瑰宝 map与set:高效数据结构的奥秘与技巧
140 0

热门文章

最新文章