Set接口

Set接口

Set接口继承自Collection接口,表示一组不重复的元素。Set接口的特点是不允许包含重复的元素,且没有定义元素的顺序。

HashSet<String> hashSet = new HashSet<>();
hashSet.add("java");
hashSet.add("python");
hashSet.add("php");
hashSet.add("c++");
System.out.println(hashSet);
输出:[python, c++, java, php]

Set接口有以下常用的实现类:

  1. HashSet:使用哈希表实现,不保证元素的顺序,允许使用null元素。
  2. LinkedHashSet:使用哈希表和链表实现,保证元素按照插入顺序排序。
  3. TreeSet:使用红黑树实现,保证元素按照自然顺序或指定的Comparator进行排序。

Set接口定义了一系列常用的方法,包括:

  1. add(E e):向集合中添加元素,如果元素已存在则不添加。
  2. remove(Object o):从集合中移除指定元素。
  3. contains(Object o):判断集合中是否包含指定元素。
  4. size():返回集合中元素的个数。
  5. isEmpty():判断集合是否为空。
  6. clear():清空集合中的所有元素。
  7. iterator():返回一个迭代器,用于遍历集合中的元素。

HashSet

HashSet的实现原理主要依赖于HashMap。

HashSet的实现原理:

  1. 内部数据结构:HashSet内部使用一个HashMap来存储元素,其中元素作为HashMap的键,值则为一个固定的Object对象。
  2. 哈希码和哈希表:当向HashSet中添加元素时,HashSet会先调用元素的hashCode()方法来获取元素的哈希码,然后根据哈希码计算元素在哈希表中的存储位置。
  3. 解决哈希冲突:由于不同的元素可能会有相同的哈希码,所以可能会发生哈希冲突。当发生哈希冲突时,HashSet会使用链表的方式来解决,即在冲突的位置上,将新元素添加到链表的末尾。
  4. 初始容量和负载因子:HashSet的初始容量默认为16,负载因子默认为0.75。当HashSet中的元素数量超过了负载因子与容量的乘积时,HashSet会自动进行扩容,即重新调整哈希表的大小。
  5. 扩容:扩容操作会创建一个新的哈希表,并将原哈希表中的元素重新分配到新的哈希表中。这个过程涉及到重新计算元素的哈希码和重新分配存储位置,以保证元素在新哈希表中的位置正确。
  6. 迭代顺序:由于HashSet使用哈希表存储元素,所以HashSet中的元素没有固定的顺序,不会按照元素的插入顺序或者排序规则进行存储和访问。

HashSet类的常用方法基本上都是通过调用HashMap的相应方法来实现的,比如add()方法会调用HashMap的put()方法,remove()方法会调用HashMap的remove()方法,contains()方法会调用HashMap的containsKey()方法等。

LinkedHashSet

LinkedHashSet的实现原理基本上与HashSet相同,都是使用HashMap来存储元素。不同之处在于LinkedHashSet使用LinkedHashMap来实现,LinkedHashMap是HashMap的子类,它在HashMap的基础上增加了一个双向链表来维护元素的插入顺序。

HashSet<String> linkedHashSet = new LinkedHashSet<>();
linkedHashSet.add("java");
linkedHashSet.add("python");
linkedHashSet.add("php");
linkedHashSet.add("c++");
System.out.println(linkedHashSet);
输出:[java, python, php, c++] //按插入顺序输出

具体实现原理如下:

  1. 内部数据结构:LinkedHashSet内部使用一个LinkedHashMap来存储元素,其中元素作为LinkedHashMap的键,值则为一个固定的Object对象。
  2. 哈希码和哈希表:当向LinkedHashSet中添加元素时,LinkedHashSet会先调用元素的hashCode()方法来获取元素的哈希码,然后根据哈希码计算元素在哈希表中的存储位置。
  3. 解决哈希冲突:由于不同的元素可能会有相同的哈希码,所以可能会发生哈希冲突。当发生哈希冲突时,LinkedHashSet会使用链表的方式来解决,即在冲突的位置上,将新元素添加到链表的末尾。
  4. 双向链表:LinkedHashSet使用双向链表来维护元素的插入顺序。在LinkedHashMap中,每个节点除了包含键值对信息外,还包含了前驱节点和后继节点的引用,通过这些引用可以实现元素的有序访问。

LinkedHashSet类的常用方法基本上都是通过调用LinkedHashMap的相应方法来实现的,比如add()方法会调用LinkedHashMap的put()方法,remove()方法会调用LinkedHashMap的remove()方法,contains()方法会调用LinkedHashMap的containsKey()方法等。

TreeSet

TreeSet基于红黑树数据结构来存储元素,并且可以根据元素的自然顺序或者指定的Comparator来进行排序。

Set<String> linkedHashSet = new TreeSet<>();
linkedHashSet.add("java");
linkedHashSet.add("python");
linkedHashSet.add("php");
linkedHashSet.add("c++");
System.out.println(linkedHashSet);
输出:[c++, java, php, python]

也可自定义排序方式:

Set<String> linkedHashSet = new TreeSet<>(new Comparator<String>() {
    @Override
    public int compare(String o1, String o2) {
        return o1.length()-o2.length(); // 按字符串长度排序
    }
});
linkedHashSet.add("java");
linkedHashSet.add("python");
linkedHashSet.add("php");
linkedHashSet.add("c++");
System.out.println(linkedHashSet);

TreeSet会将次序相同的元素看作同一元素并去重:

输出:[php, java, python]

TreeSet的实现原理如下:

  1. 内部数据结构:TreeSet内部使用的是TreeMap来存储元素,其中元素作为TreeMap的键,值则为一个固定的Object对象。
  2. 红黑树:TreeSet使用红黑树数据结构来存储元素。红黑树是一种自平衡的二叉搜索树,它保持了元素的有序性,并且在插入、删除和查找操作上具有较好的性能。
  3. 排序方式:TreeSet根据元素的自然顺序(通过实现Comparable接口)或者指定的Comparator来进行排序。在构造TreeSet对象时,可以传入一个Comparator对象来指定排序规则。
  4. 添加和删除操作:当向TreeSet中添加或删除元素时,TreeSet会根据排序规则将元素插入或删除到红黑树的适当位置。
  5. 迭代顺序:由于TreeSet使用红黑树存储元素,所以TreeSet中的元素会按照排序规则进行遍历,即按照元素的自然顺序或者指定的Comparator进行遍历。
  • 12
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

林小果呀

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值