当前位置:   article > 正文

数据结构-(Map和Set)超详细_set 和 map 数据结构

set 和 map 数据结构

目录

1.什么是Map?

1.2关于Map.Entry的说明,>

1.3Map 的常用方法说明

1.4TreeMap的使用案例

2.什么是Set?

2.1Set的常见方法

2.2TreeSet的使用案例

3.哈希表

3.1 概念

3.2实现代码 

3.3和 java 类集的关系


1.什么是Map?

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

1.2关于Map.Entry<K, V>的说明

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

1.3Map 的常用方法说明

注意:
1. Map 是一个接口,不能直接实例化对象 ,如果 要实例化对象只能实例化其实现类 TreeMap 或者 HashMap
2. Map 中存放键值对的 Key 是唯一的, value 是可以重复的
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 的区别.

1.4TreeMap的使用案例

  1. import java.util.TreeMap;
  2. import java.util.Map;
  3. public static void TestMap(){
  4. Map<String, String> m = new TreeMap<>();
  5. // put(key, value):插入key-value的键值对
  6. // 如果key不存在,会将key-value的键值对插入到map中,返回null
  7. m.put("林冲", "豹子头");
  8. m.put("鲁智深", "花和尚");
  9. m.put("武松", "行者");
  10. m.put("宋江", "及时雨");
  11. String str = m.put("李逵", "黑旋风");
  12. System.out.println(m.size());
  13. System.out.println(m);
  14. // put(key,value): 注意key不能为空,但是value可以为空
  15. // key如果为空,会抛出空指针异常
  16. //m.put(null, "花名");
  17. str = m.put("无名", null);
  18. System.out.println(m.size());
  19. // put(key, value):
  20. // 如果key存在,会使用value替换原来key所对应的value,返回旧value
  21. str = m.put("李逵", "铁牛");
  22. // get(key): 返回key所对应的value
  23. // 如果key存在,返回key所对应的value
  24. // 如果key不存在,返回null
  25. System.out.println(m.get("鲁智深"));
  26. System.out.println(m.get("史进"));
  27. //GetOrDefault(): 如果key存在,返回与key所对应的value,如果key不存在,返回一个默认值
  28. System.out.println(m.getOrDefault("李逵", "铁牛"));
  29. System.out.println(m.getOrDefault("史进", "九纹龙"));
  30. System.out.println(m.size());
  31. //containKey(key):检测key是否包含在Map中,时间复杂度:O(logN)
  32. // 按照红黑树的性质来进行查找
  33. // 找到返回true,否则返回false
  34. System.out.println(m.containsKey("林冲"));
  35. System.out.println(m.containsKey("史进"));
  36. // containValue(value): 检测value是否包含在Map中,时间复杂度: O(N)
  37. // 找到返回true,否则返回false
  38. System.out.println(m.containsValue("豹子头"));
  39. System.out.println(m.containsValue("九纹龙"));
  40. // 打印所有的key
  41. // keySet是将map中的key防止在Set中返回的
  42. for(String s : m.keySet()){
  43. System.out.print(s + " ");
  44. }
  45. System.out.println();
  46. // 打印所有的value
  47. // values()是将map中的value放在collect的一个集合中返回的
  48. for(String s : m.values()){
  49. System.out.print(s + " ");
  50. }
  51. System.out.println();
  52. // 打印所有的键值对
  53. // entrySet(): 将Map中的键值对放在Set中返回了
  54. for(Map.Entry<String, String> entry : m.entrySet()){
  55. System.out.println(entry.getKey() + "--->" + entry.getValue());
  56. }
  57. System.out.println();
  58. }

2.什么是Set?

      不包含重复元素的集合。更正式地说,设置 不包含一对元素,并且最多包含一个 null 元素。Set 接口除了这些规定之外,还放置了其他规定 继承自 Collection 接口,在 all 的合约上 构造函数以及 add、equals 和 hashCode 方法的合约。其他继承方法的声明包括 为方便起见,此处也包括在内。

2.1Set的常见方法

注意:
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 的区别

2.2TreeSet的使用案例

  1. import java.util.TreeSet;
  2. import java.util.Iterator;
  3. import java.util.Set;
  4. public static void TestSet(){
  5. Set<String> s = new TreeSet<>();
  6. // add(key): 如果key不存在,则插入,返回ture
  7. // 如果key存在,返回false
  8. boolean isIn = s.add("apple");
  9. s.add("orange");
  10. s.add("peach");
  11. s.add("banana");
  12. System.out.println(s.size());
  13. System.out.println(s);
  14. isIn = s.add("apple");
  15. // add(key): key如果是空,抛出空指针异常
  16. //s.add(null);
  17. // contains(key): 如果key存在,返回true,否则返回false
  18. System.out.println(s.contains("apple"));
  19. System.out.println(s.contains("watermelen"));
  20. // remove(key): key存在,删除成功返回true
  21. // key不存在,删除失败返回false
  22. // key为空,抛出空指针异常
  23. s.remove("apple");
  24. System.out.println(s);
  25. s.remove("watermelen");
  26. System.out.println(s);
  27. Iterator<String> it = s.iterator();
  28. while(it.hasNext()){
  29. System.out.print(it.next() + " ");
  30. }
  31. System.out.println();
  32. }

3.哈希表

3.1 概念

        顺序结构以及平衡树 中,元素关键码与其存储位置之间没有对应的关系,因此在 查找一个元素时,必须要经过关键 码的多次比较 顺序查找时间复杂度为 O(N) ,平衡树中为树的高度,即 O( ) ,搜索的效率取决于搜索过程中 元素的比较次数。
        理想的搜索方法:可以 不经过任何比较,一次直接从表中得到要搜索的元素 如果构造一种存储结构,通过某种函 (hashFunc) 使元素的存储位置与它的关键码之间能够建立一一映射的关系,那么在查找时通过该函数可以很快 找到该元素
当向该结构中:
插入元素
根据待插入元素的关键码,以此函数计算出该元素的存储位置并按此位置进行存放
搜索元素
对元素的关键码进行同样的计算,把求得的函数值当做元素的存储位置,在结构中按此位置取元素比较,若 关键码相等,则搜索成功 该方式即为哈希( 散列 ) 方法, 哈希方法中使用的转换函数称为哈希 ( 散列 ) 函数,构造出来的结构称为哈希表 (Hash Table)( 或者称散列表 )

3.2实现代码 

  1. package 哈希;
  2. import java.util.Arrays;
  3. public class HashBuck {
  4. //链表节点
  5. static class Node {
  6. public int key;
  7. public int val;
  8. public Node next;
  9. public Node(int key, int val) {
  10. this.key = key;
  11. this.val = val;
  12. }
  13. }
  14. public Node[] array;
  15. public int usedSzie; //存放了多少个数据
  16. public static final float DEFAULT_LOAD_FACTOR = 0.75f;
  17. public HashBuck(){
  18. array = new Node[10];
  19. }
  20. public void put(int key,int val){
  21. int index = key%array.length;
  22. //遍历index下标的链表 是否更新value 不存在 进行 头插法 插入数据
  23. Node cur = array[index];
  24. while (cur!= null){
  25. if(cur.key == key){
  26. //更新value
  27. cur.val = val;
  28. return;
  29. }
  30. cur = cur.next;
  31. }
  32. //cur == null 链表遍历完成 没有找到这个key
  33. Node node = new Node(key, val);
  34. node.next = array[index];
  35. array[index] = node;
  36. usedSzie++;
  37. if(doLoadFactor()> DEFAULT_LOAD_FACTOR){
  38. //扩容
  39. resize();
  40. }
  41. }
  42. private void resize(){
  43. Node[] newArray = new Node[2*array.length];
  44. //遍历原来的数组
  45. for (int i = 0; i < array.length; i++) {
  46. Node cur = array[i];
  47. while (cur != null){
  48. Node tmp = cur.next;
  49. int newIndex = cur.key % newArray.length;//新数组的下标
  50. //采用头插法 插入到新数组的 newIndex下标
  51. cur.next = newArray[newIndex];
  52. newArray[newIndex] = cur;
  53. }
  54. }
  55. array =newArray;
  56. }
  57. public int get(int key){
  58. int index = key%array.length;
  59. //遍历index下标的链表 是否更新value 不存在 进行 头插法 插入数据
  60. Node cur = array[index];
  61. while (cur!= null){
  62. if(cur.key == key){
  63. //更新value
  64. return cur.val;
  65. }
  66. cur = cur.next;
  67. }
  68. return -1;
  69. }
  70. private float doLoadFactor() {
  71. return usedSzie*0.1f/array.length;
  72. }
  73. }

3.3和 java 类集的关系

1. HashMap HashSet java 中利用哈希表实现的 Map Set
2. java 中使用的是哈希桶方式解决冲突的
3. java 会在冲突链表长度大于一定阈值后,将链表转变为搜索树(红黑树)
4. java 中计算哈希值实际上是调用的类的 hashCode 方法,进行 key 的相等性比较是调用 key equals 方 法。所以如果要用自定义类作为 HashMap key 或者 HashSet 的值, 必须覆写 hashCode equals ,而且要做到 equals 相等的对象, hashCode 一定是一致的。
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/570900
推荐阅读
相关标签
  

闽ICP备14008679号