一.了解搜索
1.概念及使用场景
Map和Set是一种专门用来进行搜索的容器或者数据结构,其搜索的效率与其具体的实例化子类有关。常见的搜索方式有:
①直接遍历:时间复杂度为O(N),元素如果多的话效率会很慢
②二分查找:时间复杂度为O(log2N),前提是搜索前必须要求序列是有序的
上述查找方式比较适合静态类型的查找,即一般不会对区间进行插入和删除操作,而现实情况中的查找如:根据姓名查找考试成绩;通讯录的根据姓名查找电话号码;不重复集合,即需要先搜索关键字是否已经在集合中,类似这样的在查找时也会进行一些插入和删除操作的即动态查找。Map和Set即是一种适合动态查找的集合容器。
2.模型
一般将搜索的数据称为关键字(key),和关键字对应的值(value),将其称为key-value的键值对,有两种模型:
①纯key模型:即Set要解决的事情,只需要判断关键字是否在集合中即可,没有对应的value值
②key-value模型:即Map要解决的事情,需要根据指定的key找到关联的value
Map和Set都是接口,实例化要实例化具体的实现类
二.Map的使用
1.Map说明
由上图可知,Map是一个接口类,该类没有继承自Collection,该类中存储的是<k,v>结构的键值对,并且k一定是唯一的,不能重复。
2.关于Map.Entry<K,V>的说明
Map.Entry<K,V>是Map内部实现的用来存放<key,value>键值对映射关系的内部类,该类主要提供了<key,value>的获取,value的设置以及key的比较方式
方法 | 解释 |
---|---|
K getKey() | 返回entry中的key |
V getValue() | 返回entry中的value |
V setValue(V value) | 将键值对中的value替换为指定value |
注意:Map.Entry<k,v>并没有提供设置key的方法
3.Map的常用方法说明
方法 | 解释 |
---|---|
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< 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 |
注意:
①Map是一个接口,不能实例化对象,如果要实例化对象只能实例化其实现类TreeMap或者HashMap
②Map中存放键值对的key是唯一的,value是可以重复的
③在Map中插入键值对时,TreeMap的键不能为空,HashMap 的键可以为空。value都可以为空
④Map中的key可以全部分离出来,存储到Set中来进行访问
⑤Map中的value可以全部分离出来,存储在Collection的任何一个子集合中
⑥Map中键值对的key不能直接修改,value可以修改,如果要修改key,要先将key删除掉,然后再进行重新插入
⑦TreeMap和HashMap的区别
三.Set的使用
1.Set说明
Set继承自Collection,是一个接口,Set中只存储key
2.Set常用方法
方法 | 解释 |
---|---|
boolean add(E e) | 添加元素,但重复元素不会被添加成功 |
void clear() | 清空集合 |
boolean contains(Object o) | 判断o是否在集合中 |
Iterator< E > iterator() | 返回迭代器 |
boolean remove(Object o) | 删除集合中的o |
int size() | 返回集合中元素个数 |
boolean isEmpty() | 检测Set是否为空,空返回true,否则返回false |
Object[] toArray() | 将Set中的元素转换为数组返回 |
boolean containsAll(Collection)<?> c | 集合c中的元素是否在set中全部存在,是返回true,否则返回false |
boolean addAll(Collection<? extends E> c) | 将集合c中的元素添加到set中,可以达到去重的效果 |
注意:
①Set是继承自Collection的一个接口类
②Set中只存储了key,并且要求key一定要唯一
③Set的底层是使用Map来实现的,其使用key
与Object的一个默认对象作为键值对插入到Map中
④Set最大的功能就是对集合中的元素进行去重
⑤实现Set接口的常用类有TreeSet和HashSet,还有一个LinkedHashSet(在HashSet的基础上维护了一个双向链表来记录元素的插入次序)
⑥Set中的key不能修改,如果要修改,先将原来的删除,然后重新插入新的key
⑦TreeSet和HashSet的区别
HashMap的应用:找出数组中只出现一次的数字
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
int num=sc.nextInt();
int[] arr=new int[num];
for(int i=0;i<num;i++){
arr[i]=sc.nextInt();
}
Map<Integer,Integer> map=new HashMap<>();
for(int i=0;i<arr.length;i++){
int a=arr[i];
if(!map.containsKey(a)){
//不包含键,直接放入
map.put(a,1);
}else{
//包含键,即对键的值进行加一操作再次放入
int count=map.get(a);
map.put(a,count+1);
}
}
//遍历找到值为1的键
for(Map.Entry<Integer,Integer> entry:map.entrySet()){
if(entry.getValue()==1){
System.out.println(entry.getKey());
}
}
}
}
}
LinkedHashSet的应用:序列中整数去重
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
while(sc.hasNext()){
int num=sc.nextInt();
int[] arr=new int[num];
for(int i=0;i<num;i++){
arr[i]=sc.nextInt();
}
//linkedHashSet是在hashset基础上加了双向链表记录键插入次序
Set<Integer> set=new LinkedHashSet<>();
//放入set中的键不会出现重复
for(int i=0;i<num;i++){
set.add(arr[i]);
}
//迭代器遍历
Iterator it=set.iterator();
while(it.hasNext()){
System.out.print(it.next()+" ");
}
System.out.println();
}
}
}