Java中Map和Set的常見(jiàn)用法舉例
一、Map和Set的概念
Map和set是一種專門用來(lái)進(jìn)行搜索的容器或者數(shù)據(jù)結(jié)構(gòu),其搜索的效率與其具體的實(shí)例化子類有關(guān),常見(jiàn)的搜索方式如下:
1.直接遍歷,時(shí)間復(fù)雜度為O(N),元素如果比較多效率會(huì)非常慢
2.二分查找,時(shí)間復(fù)雜度為O(logN) ,但搜索前必須要求序列是有序的
上述排序比較適合靜態(tài)類型的查找,即一般不會(huì)對(duì)區(qū)間進(jìn)行插入和刪除操作了,而現(xiàn)實(shí)中的查找比如:
1.根據(jù)姓名查詢考試成績(jī)
2.通訊錄,即根據(jù)姓名查詢聯(lián)系方式
3.不重復(fù)集合,即需要先搜索關(guān)鍵字是否已經(jīng)在集合中
可能在查找時(shí)進(jìn)行一些插入和刪除的操作,即動(dòng)態(tài)查找,那上述兩種方式就不太適合了,下面介紹的Map和Set是一種適合動(dòng)態(tài)查找的集合容器
二、模型
一般把搜索的數(shù)據(jù)稱為關(guān)鍵字(Key),和關(guān)鍵字對(duì)應(yīng)的稱為值(Value),將其稱為Key-Value的鍵值對(duì),所以模型有兩種:
1.純Key模型
有一個(gè)英文詞典,快速查找一個(gè)單詞是否在詞典中
快速查找某個(gè)名字在不在通訊錄中
2.Key-Value 模型
統(tǒng)計(jì)文件中每個(gè)單詞出現(xiàn)的次數(shù),統(tǒng)計(jì)結(jié)果是每個(gè)單詞都有與其對(duì)應(yīng)的次數(shù):<單詞,單詞出現(xiàn)的次數(shù)>
梁山好漢的江湖綽號(hào):每個(gè)好漢都有自己的江湖綽號(hào)
而Map中存儲(chǔ)的就是key-value的鍵值對(duì),Set中只存儲(chǔ)了Key
三、Map的說(shuō)明
Map是一個(gè)接口類,該類沒(méi)有繼承自Collection,該類中存儲(chǔ)的是<K,V>結(jié)構(gòu)的鍵值對(duì),并且K一定是唯一的,不能重復(fù)
3.1 Map.Entry<K, V>的說(shuō)明
Map.Entry<K, V> 是Map內(nèi)部實(shí)現(xiàn)的用來(lái)存放<key, value>鍵值對(duì)映射關(guān)系的內(nèi)部類,該內(nèi)部類中主要提供了<key, value>的獲取,value的設(shè)置以及Key的比較方式
方法 | 解釋 |
---|---|
K getKey() | 返回entry中的key |
V getValue() | 返回entry中的value |
V setValue(V value) | 將鍵值對(duì)中的value替換為指定value |
注意:Map.Entry<K,V>并沒(méi)有提供設(shè)置Key的方法
3.2 Map 的常用方法
方法 | 解釋 |
---|---|
V get(Object key) | 返回key對(duì)應(yīng)的value |
V getOrDefault(Object key, V defaultValue) | 返回key對(duì)應(yīng)的value,key不存在,返回默認(rèn)值 |
V put(K key, V value) | 設(shè)置key對(duì)應(yīng)的value |
V remove(Object key) | 刪除key對(duì)應(yīng)的映射關(guān)系 |
Set< K > keySet() | 返回所有key的不重復(fù)集合 |
Collection< V > values() | 返回所有value的可重復(fù)集合 |
Set<Map.Entry<K,V>>entrySet() | 返回所有的key-value映射關(guān)系 |
boolean containsKey(Object key) | 判斷是否包含key |
boolean containsValue(Object Value) | 判斷是否包含value |
注意:
1.Map是一個(gè)接口,不能直接實(shí)例化對(duì)象,如果要實(shí)例化對(duì)象只能實(shí)例化其實(shí)現(xiàn)類TreeMap或者HashMap
2.Map中存放鍵值對(duì)的Key是唯一的,value是可以重復(fù)的
3.在TreeMap中插入鍵值對(duì)時(shí),key不能為空,否則就會(huì)拋NullPointerException異常,value可以為空。但是HashMap的key和value都可以為空
4.Map中的Key可以全部分離出來(lái),存儲(chǔ)到Set中來(lái)進(jìn)行訪問(wèn)(因?yàn)镵ey不能重復(fù))
5.Map中的value可以全部分離出來(lái),存儲(chǔ)在Collection的任何一個(gè)子集合中(value可能有重復(fù))
6.Map中鍵值對(duì)的Key不能直接修改,value可以修改,如果要修改key,只能先將該key刪除掉,然后再來(lái)進(jìn)行重新插入
四、Set的說(shuō)明
Set與Map主要的不同有兩點(diǎn):Set是繼承自Collection的接口類,Set中只存儲(chǔ)了Key
4.1 Set的常用方法
方法 | 解釋 |
---|---|
boolean add(E e) | 添加元素,但重復(fù)元素不會(huì)被添加成功 |
void clear() | 清空集合 |
boolean contains(Object o) | 判斷o是否在集合中 |
lterator< E > iterator() | 返回迭代器 |
boolean remove(Object o) | 刪除集合中的o |
int size() | 返回set中元素的個(gè)數(shù) |
boolean isEmpty() | 檢測(cè)set是否為空,空返回true,否則返回false |
Object[] toArray() | 將set中的元素轉(zhuǎn)換為數(shù)組返回 |
boolean containsAll(Collection<?>c) | 集合c中的元素是否在set中全部存在,是返回true,否則返回false |
boolean addAll(Conllection<? extends E>c) | 將集合c中的元素添加到set中,可以達(dá)到去重的效果 |
注意:
1.Set是繼承自Collection的一個(gè)接口類
2.Set中只存儲(chǔ)了key,并且要求key一定要唯一
3.TreeSet的底層是使用Map來(lái)實(shí)現(xiàn)的,其使用key與Object的一個(gè)默認(rèn)對(duì)象作為鍵值對(duì)插入到Map中的
4.Set最大的功能就是對(duì)集合中的元素進(jìn)行去重
5.實(shí)現(xiàn)Set接口的常用類有TreeSet和HashSet,還有一個(gè)LinkedHashSet,LinkedHashSet是在HashSet的基礎(chǔ)上維護(hù)了一個(gè)雙向鏈表來(lái)記錄元素的插入次序
6.Set中的Key不能修改,如果要修改,先將原來(lái)的刪除掉,然后再重新插入
7.TreeSet中不能插入null的key,HashSet可以
附:一些有關(guān) Map 和 Set 的題目
1. 統(tǒng)計(jì)一組數(shù)據(jù)中的每個(gè)數(shù)據(jù)出現(xiàn)了多少次
/** * 統(tǒng)計(jì)一組數(shù)據(jù)中的每個(gè)數(shù)據(jù)出現(xiàn)了多少次 */ import java.util.HashMap; import java.util.Map; public class Test { public static void main(String[] args) { char[] arr = {'a','c','e','c','b','d','f','c','d'}; Map<Character,Integer> map = computer(arr); System.out.println(map); } public static Map<Character,Integer> computer(char[] arr){ Map<Character,Integer> map = new HashMap<>(); //如果在 map 中沒(méi)有數(shù)組對(duì)應(yīng)的 Key,那么就添加 1個(gè) Key 進(jìn)去 //如果在 map 中包含了和數(shù)組對(duì)應(yīng)的 Key,且 Key 對(duì)應(yīng) count個(gè) Val, //那么就添加 count + 1個(gè) Key 進(jìn)去 for (char x :arr) { if(map.containsKey(x)){ int count = map.get(x); map.put(x, count+1); }else { map.put(x,1); } } return map; } }
2. 將一組數(shù)據(jù)中多余的數(shù)據(jù)去重
/** * 將一組數(shù)據(jù)中多余的數(shù)據(jù)去重 */ import java.util.HashSet; import java.util.Set; public class Test { public static void main(String[] args) { int[] arr = {1,3,5,7,9,3,2,4,6,8,5,4,6}; Set<Integer> set = new HashSet<>(); for (int x : arr) { set.add(x); } System.out.println(set); } }
3. 找出第一個(gè)重復(fù)出現(xiàn)的數(shù)據(jù)
/** * 在一組數(shù)據(jù)中,找出第一個(gè)重復(fù)出現(xiàn)的數(shù)據(jù) */ import java.util.HashSet; import java.util.Set; public class Test6 { public static void main(String[] args) { int[] arr = {1,3,5,7,9,3,2,4,6,8,5,4,6}; Set<Integer> set = new HashSet<>(); int i = 0; //如果在添加元素到 set 之前,就已經(jīng)發(fā)現(xiàn)了 set 中包含某個(gè)數(shù)組的元素, //那么就 break for (i = 0; i < arr.length; i++) { if(set.contains(arr[i])){ break; } set.add(arr[i]); } System.out.println(arr[i]); //拿到的就是第一次出現(xiàn)的重復(fù)值 } }
4. 只出現(xiàn)一次的數(shù)字
方法一:
/** * 利用兩兩元素之間異或,最終得出的就是單獨(dú)元素 */ class Solution { public int singleNumber(int[] nums) { int x = nums[0]; for(int i= 1; i<nums.length; i++){ x = x^nums[i]; } return x; } }
方法二:
/** * 利用集合 Set * 如果集合中有相同元素,就移除,反之,就添加 */ class Solution { public int singleNumber(int[] nums) { Set<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; } }
5. 復(fù)制帶隨機(jī)指針的鏈表
本題需要詳細(xì)掌握 Map 的操作,與其對(duì)應(yīng)的映射關(guān)系,才能將本題理解到位。
/** * 通過(guò) Map 的映射關(guān)系 * 知道了 Key 的狀態(tài),實(shí)現(xiàn) Value 的狀態(tài) * 即通過(guò)舊節(jié)點(diǎn)之間的關(guān)系,實(shí)現(xiàn)新節(jié)點(diǎn)之間的關(guān)系 */ class Solution { public Node copyRandomList(Node head) { if(head == null) return null; //Key - 舊節(jié)點(diǎn),Value - 新節(jié)點(diǎn) Map<Node,Node> map = new HashMap<>(); Node cur = head; //1. 創(chuàng)建新的節(jié)點(diǎn) while(cur != null){ map.put(cur, new Node(cur.val)); cur = cur.next; } cur = head; //2. 連接各個(gè)節(jié)點(diǎn) while(cur != null){ map.get(cur).next = map.get(cur.next); map.get(cur).random = map.get(cur.random); cur = cur.next; } return map.get(head); } }
6. 寶石與石頭
方法一
/** * 方法一 * 1. 將 jewels 字符串中的字符放入集合 set 中 * 2. 查看集合 set 中是否包含 stones 字符數(shù)組中字符 * 3. 用 count 計(jì)數(shù),最后返回 */ class Solution { public int numJewelsInStones(String jewels, String stones) { Set<Character> set = new HashSet<>(); for(char x:jewels.toCharArray()){ //1. set.add(x); } int count = 0; for(char j:stones.toCharArray()){ //2. if(set.contains(j)){ count++; } } return count; //3. } }
方法二
/** * 方法二 * 兩層 for 循環(huán) */ class Solution { public int numJewelsInStones(String jewels, String stones) { int count = 0; for(int i=0; i<jewels.length(); i++){ for(int j=0; j<stones.length();j++){ if( jewels.charAt(i) == stones.charAt(j) ){ count++; } } } return count; } }
7. 鍵盤壞了的鍵
import java.util.ArrayList; import java.util.HashSet; import java.util.Scanner; import java.util.Set; /** * 1. 將實(shí)際輸入的文字 str2 放在集合 set 中 * 2. for 循環(huán)遍歷應(yīng)該輸入的文字 str1, * 若集合 set 不包含某個(gè)字符,且線性表之前也未出現(xiàn)該字符,就輸出打印 * 3. 將步驟 2 中不包含的字符放入順序表中,以便下一次判斷 */ public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); String str1 = scanner.nextLine(); //應(yīng)該輸入的文字 String str2 = scanner.nextLine(); //實(shí)際輸入的文字 out(str1,str2); } public static void out(String str1, String str2){ Set<Character> set = new HashSet<>(); ArrayList<Character> list = new ArrayList<>(); for (char x:str2.toUpperCase().toCharArray()) { set.add(x); //1. } for(char x:str1.toUpperCase().toCharArray()){ //2. if(!set.contains(x) && !list.contains(x)){ System.out.print(x); } list.add(x); //3. } } }
8. 前K個(gè)高頻單詞
class Solution { public List<String> topKFrequent(String[] words, int k) { Map<String,Integer> hashMap =new HashMap<>(); for(String s: words) { if(hashMap.get(s) == null) { hashMap.put(s,1); }else { hashMap.put(s,hashMap.get(s)+1); } } //2、建立小根堆 PriorityQueue<Map.Entry<String,Integer>> minHeap = new PriorityQueue<>( k, new Comparator<Map.Entry<String, Integer>>() { @Override public int compare(Map.Entry<String, Integer> o1, Map.Entry<String, Integer> o2) { if(o1.getValue().compareTo(o2.getValue()) == 0) { return o2.getKey().compareTo(o1.getKey()); } return o1.getValue().compareTo(o2.getValue()); } } ); //3、遍歷hashMap 把里面 的數(shù)據(jù) 放到小根堆 for(Map.Entry<String,Integer> entry : hashMap.entrySet()) { if(minHeap.size() < k) { minHeap.offer(entry); }else { //小根堆放滿了K個(gè),下一個(gè)entry和堆頂元素比較 Map.Entry<String,Integer> top = minHeap.peek(); //堆頂?shù)念l率小于當(dāng)前entry的頻率 就出隊(duì) 然后入隊(duì)entry if(top.getValue().compareTo(entry.getValue()) < 0) { minHeap.poll(); minHeap.add(entry); }else { //頻率相同的情況 if(top.getValue().compareTo(entry.getValue()) == 0) { if(top.getKey().compareTo(entry.getKey()) > 0) { minHeap.poll(); minHeap.add(entry); } } } } } //4、 此時(shí)小根堆當(dāng)中已經(jīng)有了結(jié)果 //System.out.println(minHeap); List<String> ret = new ArrayList<>(); for (int i = 0; i < k; i++) { String key = minHeap.poll().getKey(); ret.add(key); } Collections.reverse(ret); //System.out.println("ret: "+ret); return ret; } }
總結(jié)
到此這篇關(guān)于Java中Map和Set的常見(jiàn)用法舉例的文章就介紹到這了,更多相關(guān)Java Map和Set內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
在SpringBoot中實(shí)現(xiàn)一個(gè)訂單號(hào)生成系統(tǒng)的示例代碼
在Spring Boot中設(shè)計(jì)一個(gè)訂單號(hào)生成系統(tǒng),主要考慮到生成的訂單號(hào)需要滿足的幾個(gè)要求:唯一性、可擴(kuò)展性、以及可能的業(yè)務(wù)相關(guān)性,本文給大家介紹了幾種常見(jiàn)的解決方案及相應(yīng)的示例代碼,需要的朋友可以參考下2024-02-02幾句話說(shuō)清session,cookie和token的區(qū)別及說(shuō)明
這篇文章主要介紹了幾句話說(shuō)清session,cookie和token的區(qū)別及說(shuō)明,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-12-12SpringCloud-Alibaba-Sentinel服務(wù)降級(jí),熱點(diǎn)限流,服務(wù)熔斷
這篇文章主要介紹了SpringCloud-Alibaba-Sentinel服務(wù)降級(jí),熱點(diǎn)限流,服務(wù)熔斷,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12全面詳解java代碼重構(gòu)與設(shè)計(jì)模式
這篇文章主要為大家介紹了全面詳解java代碼重構(gòu)與設(shè)計(jì)模式的全面詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2023-06-06Spring Boot 2.X 快速集成單元測(cè)試解析
這篇文章主要介紹了Spring Boot 2.X 快速集成單元測(cè)試解析,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-08-08Springboot文件上傳功能簡(jiǎn)單測(cè)試
這篇文章主要介紹了Springboot文件上傳功能簡(jiǎn)單測(cè)試,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-05-05JavaWeb實(shí)現(xiàn)簡(jiǎn)單上傳文件功能
這篇文章主要為大家詳細(xì)介紹了JavaWeb實(shí)現(xiàn)簡(jiǎn)單上傳文件功能,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-06-06