set集合&&hashMap总结

发布时间 2023-12-28 20:48:43作者: ZWJAS

总结

实现set接口的集合

set集合:无序不重复
不重复(去重):元素放入集合之前或做判断
无序:存取不一致

1、讲解set的实现类
HashSet:底层使用哈希表来实现(底层是一个数组,数组里面保存一个单向链表)的集合
不允许元素重复,元素是无序的

  • HashSet的去重机制(怎么去除重复)
    第一步:将要添加到HashSet集合元素的hashCode值拿到
    第二步:在集合去查找是否存在这个hashCode值
    不存在,说明这个元素在集合中不存在,可以执行添加
    存在,就来让这个元素.equals(hashCode值相同元素),

    ​ 不相等false,说明这个元素在集合中不存在,执行添加,

    ​ 相等true,说明元素在集合中已经存在了,那就不添加

    注意:如果是自己创建的类,要重写hashCode方法和equals()方法。

    	 @Override
        public boolean equals(Object o) {
            if (this == o) return true;
            if (o == null || getClass() != o.getClass()) return false;
           Dog dog = (Dog) o;
            return Objects.equals(name, dog.name);
        }
    
        @Override
        public int hashCode() {
            return Objects.hash(name);
        }
    
  • HashSet的作用就是用来去重

  • LinkedHashSet:底层哈希表+单向链表(记录顺序):有序的HashSet

    public static void main(String[] args) {
        // 创建一个HashSet集合
        HashSet set = new HashSet(); // 哈希表(散列表)
        // 常用方法
        set.add("abc");
        set.add(true);
        set.add(123);
        set.add("波多野辰辰");
        set.add("波多野辰辰");
        set.add("波多野辰辰");
        System.out.println(set);
        // 遍历
//        for (Object o : set) {
//            System.out.println(o);
//        }
        Iterator it = set.iterator();
        while (it.hasNext()) {
            System.out.println(it.next());
        }
    }
    public static void main(String[] args) {
        // 产生10个不重复的随机数
//        HashSet set = new HashSet();
//        while (set.size() < 10) {
//            set.add((int)(Math.random() * 100 + 1));
//        }
//        System.out.println(set);

        HashSet set = new HashSet();
//        Cat d1 = new Cat("来福");
//        Cat d2 = new Cat("来福");
//        System.out.println(d1.hashCode());
//        System.out.println(d2.hashCode());

//        set.add(d1);
//        set.add(d2);
        System.out.println(set);

    }

TreeSet集合:底层使用树结构来实现的集合
TreeSet:无序不可重复
树型结构是提高查询效率,将树上的元素按大小排序
在使用TreeSet,该集合中只能放同一种类型的元素,第一个添加的元素类型,就是这个集合中能放的类型
为什么TreeSet只能放同一种类型的元素?

因为对元素进行排序,类型必须一致。
    public static void main(String[] args) {
        // 创建一个TreeSet集合
        TreeSet set = new TreeSet(); // 底层是TreeMap,基于树结构
//        set.add("abc");
//        set.add("bbc");
//        set.add(123);
//        System.out.println(set);
        set.add(20);
        set.add(20);
        set.add(2);
        set.add(27);
        set.add(12);
        set.add(200);
        System.out.println(set);

    }
  1. 怎样去重(去除重复的机制)
    通过两个接口来完成
    添加元素到集合,这个元素会和集合里面所有的元素依次调用compareTo()进行比较,返回 0,就说明该元素在集合已经存在了,就不添加了

  2. 排序方法

    自然排序:元素会根据类里面写compareTo()的代码来进行排序

    注意:返回正数说明p1对象大于p2对象 2、返回负数说明p1小于p2 3、返回0说明p1等于p2

    System.out.println(p1.compareTo(p2)); // 1、返回正数说明p1对象大于p2对象 2、返回负数说明p1小于p2 3、返回0说明p1等于p2
    
       @Override
         public int compareTo(Object o) {
             // 对象进行大小比较其实就是对象的属性值进行比较
             Pig p = (Pig)o;
             if(!this.name.equals(p.name)) { // 两个对象的名字不同,就比较name
                 return p.name.hashCode() - this.name.hashCode(); // 0 整数 负数
     //            return this.name.length() - p.name.length();
             }else if(this.age != p.age) { // name相同,age不同,就比较age
                 return p.age - this.age;
             }
             return 0; // 属性值都相等返回0
     //        return this.hashCode() - p.hashCode();
         }
    

    定制排序:实现Comparator接口,在一个单独的类里面写compareTo()的代码来进行排序

    import java.util.Comparator;
    
    public class MyCompartor implements Comparator {
        @Override
        public int compare(Object o1, Object o2) {
            Cat c1 = (Cat)o1;
            Cat c2 = (Cat)o2;
            if(!c1.getName().equals(c2.getName())) {
                return c2.getName().hashCode() - c1.getName().hashCode();
            }else if(!c1.getGender().equals(c2.getGender())) {
                return c2.getGender().hashCode() - c1.getGender().hashCode();
            }else if(c1.getAge() != c2.getAge()){
                return c2.getAge() - c1.getAge();
            }
            return 0;
        }
    }
    
    // 测试类
    import java.util.TreeSet;
    
    public class CatTest {
        public static void main(String[] args) {
            Cat c1 = new Cat("咪咪", "公", 2);
            Cat c2 = new Cat("哆哆", "母", 5);
            Cat c3 = new Cat("啦啦", "公", 1);
    //        TreeSet set = new TreeSet(); // Comparable
            TreeSet set = new TreeSet(new MyCompartor());// Comparator:定制排序
            set.add(c1);
            set.add(c2);
            set.add(c3);
            System.out.println(set);
        }
    }
    
  3. 作用就是对元素进行排序,放入TreeSet的元素必须是同一类型,必须要实现Comparable接口

    注意:Comparable:比较对象大小的接口

    ublic class Pig implements  Comparable  {
        private String name;
        private int age;
    
        public String getName() {
            return name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Pig{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    
        @Override
        public int compareTo(Object o) {
            // 对象进行大小比较其实就是对象的属性值进行比较
            Pig p = (Pig)o;
            if(!this.name.equals(p.name)) { // 两个对象的名字不同,就比较name
                return p.name.hashCode() - this.name.hashCode(); // 0 整数 负数
    //            return this.name.length() - p.name.length();
            }else if(this.age != p.age) { // name相同,age不同,就比较age
                return p.age - this.age;
            }
            return 0; // 属性值都相等返回0
    //        return this.hashCode() - p.hashCode();
        }
    }
    

集合小结

1、体系结构
Collection
-List:有序可重复
实现类:
-ArrayList:底层是一个数组,查改快,增删插慢
-LinkedList:底层是一个双向链表,双向队列,栈
增删插快,查改慢
对首尾操作快
栈:push(),pop()
-Vector:线程安全的动态数组
-Set:无序不可重复
-HashSet:底层是一个哈希表,去重的原理:hashCode + equals,作用:用来去重的
-LinkedHashSet:哈希表+单向链表,可以维护顺序
-TreeSet:底层是树结构,作用:用来排序
要求:同一种类型,要使用Comparable或Comparator,排序

2、使用场景:
集合用:ArrayList,需要大频率的增删插,将ArrayList转换为LinkedList
需要去重,将ArrayList转换HashSet,如果需要保证顺序,转换为LinkedHashSet
需要排序,将ArrayList转换为TreeSet

​ 集合:保存一个值

Map集合

Map集合: 保存一对值

Map:映射(键值对,由一个键指向一个值)

Map中键不能重复,值可以重复,一个键只能指向一个值

Map是映射的顶级父类,是一个接口

Map的实现类
HashMap:就是一个哈希表(散列表)
底层是一个:数组,数组中保存了一个单向链表,链表在满足条件下回转为树结构(红黑树)
在数组保存那些信息:键的hashCode、键、值、下一个对象

创建HashMap集合对象

​ 创建长度为16的数组,数组的每一个元素有一个空链表,map保存的是一对值

HashMap map = new HashMap();

​ put(K key, V value) : 向map集合添加一对值

map.put("3838438", "蘋蘋");

存放值的过程

​ key:"3838438"
1. 获取键的hashCode,假设hashCode是19
2. 计算这对值放入数组的下标位置:用键的hash值 % 当前数组的长度,19 % 16,计算的结 果是3,那么这对值应该放入下标为3的位置
3. 判断下标为3的位置上有没有值:
​ 没有:直接将这对值放入这个位置
​ 有:将这个值接在这个位置上存在值的后面

map中键不允许重复

去重的机制:键的hashCode + equals

  1. key:"3838438",将键的哈希值获得
  2. 去这个map集合中查看有没有相同哈希值的键
    • 没有:说明键不重复
      计算放入的位置
      ......
    • 有:将这个键.equals(哈希值相同的键),结果是true,说明键已经存在,然后覆盖值,结果false

哈希碰撞(哈希冲突)

概念:计算存在的位置,这个位置上已经有值,这就是哈希碰撞

​ (HashSet的值就是存在HashMap的键上,所以HashSet的值不可重复)

链表转为红黑树的过程
当一个链表上的元素个数(链表的节点数)大于等于8个,看这个集合中元素个是否大于等于64

  • 没有:底层数组做一次扩容:当前长度的2倍
  • 有:这个链表就会形成红黑树

当我们做删除的时候
原来是红黑树的,如果元素个数小于等于6个,那么这个红黑树又会转为链表