数据结构之Map&Set

简介: 数据结构之Map&Set

1667919156551.jpg

一、概念、场景及模型


Map 和 set是一种专门用来进行搜索的容器或者数据结构, Map 和 Set是一种适合动态查找的集合容器。TreeMap和TreeSet集合背后的数据结构就是搜索树,红黑树。其中TreeSet底层就是一个TreeMap。

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

1. 纯 key 模型

2. Key-Value 模型

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


二、Map的使用


Map的官方文档:Map (Java Platform SE 8 )

https://docs.oracle.com/javase/8/docs/api/java/util/Map.html

1.关于Map的说明


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

2.关于Map.Entry的说明


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

方法 说明

getKey()

返回entry 中的key

V getValue ()

返回 entry 中的 value

V setValue(V value)

将键值对中的 value 替换为指定 value


注意: Map.Entry<K,V> 并没有提供设置 Key 的方法

3.Map的常用方法

方法 说明

get(Object key)

返回key 对应的value

getOrDefault(Object key, V defaultValue)

返回 key 对应的 value  key 不存在,返回默认值
V put (K key, V value) 设置 key 对应的 value

V remove (Object key)

删除 key 对应的映射关系

Set<K> keySet ()

返回所有 key 的不重复集合

Collection<V> values ()

返回所有 value 的可重复集合

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

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

boolean containsKey (Object key)

判断是否包含 key

boolean containsValue (Object value)

判断是否包含 value


注意:

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

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

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

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

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

6. TreeMap 和 HashMap 的区别

Map TreeMap HashMap
底层结构 红黑树 哈希桶

插入/删除/查找时间

复杂度

O(logN)

O(1)

是否有序

关于 Key 有序

无序

线程安全

不安全

不安全

插入 / 删除 / 查找区别

需要进行元素比较

通过哈希函数计算哈希地址

比较与覆写

key 必须能够比较,否则会抛出 ClassCastException异常

自定义类型需要覆写 equals 和 hashCode方法

应用场景

需要 Key 有序场景下

Key 是否有序不关心,需要更高的时间性能


4.Map的遍历方式


使用最多也最简单的是for循序遍历:

HashMap<Integer,Integer> map = new HashMap<>();
           map.put(1,1);
           map.put(2,2);
            int[] arr = new int[2];
            int k = 0;
            for (Map.Entry<Integer,Integer> entry:map.entrySet()) {
                arr[k++] = entry.getKey();
            }

其实还有使用迭代遍历map、使用keySet迭代遍历map、使用entrySet遍历map这几种方式,但是觉得使用比较麻烦,直接使用for循环比较方便。


5.试题案例


统计10W个数据当中,每个数据出现的次数以及对应的关系。

public static void func3(int[] array) {
        HashMap<Integer,Integer> map = new HashMap<>();
        //1、遍历原来的数据,统计每个数据出现的次数
        for (int i = 0; i < array.length; i++) {
            int key = array[i];
            if(map.get(key) == null) {
                map.put(key,1);
            }else {
                int val = map.get(key);//key出现的 次数
                map.put(key,val+1);
            }
        }
        for (Map.Entry<Integer,Integer> entry: map.entrySet()) {
            System.out.println("key: "+entry.getKey()+" 出现了:"+entry.getValue()+"次!");
        }
    }


三、Set的使用


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


Set的官方文档:

Set (Java Platform SE 8 )

https://docs.oracle.com/javase/8/docs/api/java/util/Set.html

1.关于Set的常见方法

方法 说明

boolean add(E e)

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

void clear ()

清空集合

boolean contains (Object o)

判断 o 是否在集合中

Iterator<E> iterator ()

返回迭代器

boolean remove (Object o)

删除集合中的 o

int size()

返回 set 中元素的个数

boolean isEmpty()

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

Object[] toArray()

 set 中的元素转换为数组返回

boolean containsAll(Collection<?> c)

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

boolean addAll(Collection<? extends E> c)

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


注意:


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

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

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

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

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

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

7. Set 中不能插入 null 的 key,而Map则可以插入空的key 。

2.试题案例


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

public int singleNumber(int[] nums) {
            HashSet<Integer> set = new HashSet<>();
            for (int i = 0; i < nums.length; i++) {
                if (!set.contains(nums[i])){
                    set.add(nums[i]);
                }else {
                    set.remove(nums[i]);
                }
            }
            for (int i = 0; i < nums.length; i++) {
                if (set.contains(nums[i])){
                    return nums[i];
                }
            }
            return -1;
        }
相关文章
|
6月前
|
存储 算法 容器
set_map的实现+set/map加持秒杀高频算法题锻炼算法思维
`set`基于红黑树实现,支持有序存储、自动去重,增删查效率为O(logN)。通过仿函数可自定义排序规则,配合空间配置器灵活管理内存。不支持修改元素值,迭代器失效需注意。`multiset`允许重复元素。常用于去重、排序及查找场景。
|
6月前
|
存储 JavaScript Java
(Python基础)新时代语言!一起学习Python吧!(四):dict字典和set类型;切片类型、列表生成式;map和reduce迭代器;filter过滤函数、sorted排序函数;lambda函数
dict字典 Python内置了字典:dict的支持,dict全称dictionary,在其他语言中也称为map,使用键-值(key-value)存储,具有极快的查找速度。 我们可以通过声明JS对象一样的方式声明dict
402 2
|
9月前
|
存储 缓存 JavaScript
Set和Map有什么区别?
Set和Map有什么区别?
626 1
|
10月前
|
存储 JavaScript 前端开发
for...of循环在遍历Set和Map时的注意事项有哪些?
for...of循环在遍历Set和Map时的注意事项有哪些?
686 156
|
10月前
|
存储 C++ 容器
unordered_set、unordered_multiset、unordered_map、unordered_multimap的介绍及使用
unordered_set是不按特定顺序存储键值的关联式容器,其允许通过键值快速的索引到对应的元素。在unordered_set中,元素的值同时也是唯一地标识它的key。在内部,unordered_set中的元素没有按照任何特定的顺序排序,为了能在常数范围内找到指定的key,unordered_set将相同哈希值的键值放在相同的桶中。unordered_set容器通过key访问单个元素要比set快,但它通常在遍历元素子集的范围迭代方面效率较低。它的迭代器至少是前向迭代器。前向迭代器的特性。
567 0
|
10月前
|
编译器 C++ 容器
用一棵红黑树同时封装出map和set
再完成上面的代码后,我们的底层代码已经完成了,这时候已经是一个底层STL的红黑树了,已经已符合库里面的要求了,这时候我们是需要给他穿上对应的“衣服”,比如穿上set的“衣服”,那么这个穿上set的“衣服”,那么他就符合库里面set的要求了,同样map一样,这时候我们就需要实现set与map了。因此,上层容器map需要向底层红黑树提供一个仿函数,用于获取T当中的键值Key,这样一来,当底层红黑树当中需要比较两个结点的键值时,就可以通过这个仿函数来获取T当中的键值了。我们就可以使用仿函数了。
148 0
|
10月前
|
存储 编译器 容器
set、map、multiset、multimap的介绍及使用以及区别,注意事项
set是按照一定次序存储元素的容器,使用set的迭代器遍历set中的元素,可以得到有序序列。set当中存储元素的value都是唯一的,不可以重复,因此可以使用set进行去重。set默认是升序的,但是其内部默认不是按照大于比较,而是按照小于比较。set中的元素不能被修改,因为set在底层是用二叉搜索树来实现的,若是对二叉搜索树当中某个结点的值进行了修改,那么这棵树将不再是二叉搜索树。
359 0
|
编译器 C++ 容器
【c++丨STL】基于红黑树模拟实现set和map(附源码)
本文基于红黑树的实现,模拟了STL中的`set`和`map`容器。通过封装同一棵红黑树并进行适配修改,实现了两种容器的功能。主要步骤包括:1) 修改红黑树节点结构以支持不同数据类型;2) 使用仿函数适配键值比较逻辑;3) 实现双向迭代器支持遍历操作;4) 封装`insert`、`find`等接口,并为`map`实现`operator[]`。最终,通过测试代码验证了功能的正确性。此实现减少了代码冗余,展示了模板与仿函数的强大灵活性。
345 2
|
编译器 容器
哈希表模拟封装unordered_map和unordered_set
哈希表模拟封装unordered_map和unordered_set

热门文章

最新文章

下一篇
开通oss服务