• Set集合(超详解)


             回顾问题:

    上一期我们讲了list集合,它的一个显著特点就是读取速度快,元素可重复,可以自动扩容!!!有一个问题,在上一期中,我们使用foreach去删除元素是会发现在两个相邻的同一样的元素中会发生执行错误,如果我们没有重复相邻的两个元素,再去删除,还是会有问题,但我们如果刚好删除的是倒数第二个元素,就可以正常删除,这是为什么呢,我们一起来看看。

    下面的图都为源码:

    array list的删除方法

    大家首先看到这里的这个方法,在使用list进行foreach进行删除的时候我们就会进入到这里来,然后进行删除,那具体是怎么样的呢,其实在使用foreach进行删除的时候是调用的一个iterator来进行的,这个迭代器就是我们的array list的内部类中的iterator,它进入到这里之后会调用hasnext方法进行cursor进行一个和集合元素的长度进行比较,如果不相等就还有元素,然后接着往下走,调用next方法先去进行一个检查维护,那这个modCount是什么呢,它其实是我们的集合的大小,当我们集合元素大小发生变化是就会更着改变,例如,如果集合原本大小为5,此时插入一个元素,就变成了6.modCount也变成了6,减少一个变成4,modCount也变成了4。所以我们就会发现,在我们用foreach进行list的删除时这个检查约束过不不了就直接抛出异常了,而为什么倒数第二可以呢,以为删除它就变成倒数第一了,来不及检查约束就已经删除了,其实这也时一个特性,但它本质是一个bug。

    array list的迭代器foreach所使用的

    检查方法

    检查方法

    Set集合

    特点:

    1. 特点:无序,不重复

    2. 遍历:foreach,迭代器

    3.  扩容: 初始容量16,负载因子0.75,扩容增量1倍

     实现类

    HashSet

    特点:

    1.它存储唯一元素并允许空值,依据对象的hashcode来确定该元素是否存在

    2. 由HashMap支持

    3. 不保持插入顺序

    4. 非线程安全

    5. 性能参数:初始容量,负载因子,默认值: 初始容量16,负载因子0.75,示例:new HashSet<>(20, 0.5f);

    实例

    1. List<Integer> list = new ArrayList<Integer>();
    2. private Set<Integer> set = new HashSet<Integer>();
    3. @Before
    4. public void setup() {
    5. list.add(1);
    6. list.add(4);
    7. list.add(4);
    8. list.add(8);
    9. list.add(8);
    10. list.add(12);
    11. list.add(16);
    12. set.add(1);
    13. set.add(2);
    14. set.add(3);
    15. set.add(3);
    16. set.add(4);
    17. set.add(4);
    18. set.add(5);
    19. }
    20. @Test
    21. public void setdome01() {
    22. List<Integer> temp = new ArrayList<Integer>(new HashSet<Integer>(list));
    23. System.out.println(temp);
    24. // 结果:[16,1,4,8,12],hashset直接帮我们去重复了,因为set集合不可以出现重复的
    25. // 除了这种方法还有list的迭代器的去重复,还有最为死的for遍历,一个一个做判断删除
    26. }
    27. // HashSet其实就是一个皮包公司,都是委托
    28. @Test
    29. public void setdome02() {
    30. for (Integer ui : set) {
    31. System.out.println(ui);
    32. }
    33. // 结果:12345;
    34. // 可以看到,去重复和排序了
    35. }
    36. @Test
    37. public void setdome03() {
    38. Iterator<Integer> it = set.iterator();
    39. while (it.hasNext()) {
    40. System.out.println(it.next());
    41. }
    42. // 结果:12345
    43. }
    44. // 可以看到,我们插入的到顺序是无序的,但我们输出的却是有序的,而set是无序的,
    45. // 那为什么输出的有序呢,那是因为set的无序指的是插入的顺序是无序 ,而这的有序
    46. // 是因为hashset的有序,我们常说的有序是指插入的顺序是有序的

    TreeSet

    1. 是一个包含有序的且没有重复元素的集合

    2. 作用是提供有序的Set集合,自然排序或者根据提供的Comparator进行排序

    3. TreeSet是基于TreeMap实现的

    比较器

    1.默认自然排序

    1. 1. 默认自然排序
    2. 数据准备
    3. ts = new TreeSet<>();
    4. ts.add(1);
    5. ts.add(8);
    6. ts.add(7);
    7. ts.add(2);
    8. ts.add(4);
    9. ts.add(6);
    10. ts.add(3);
    11. @Test
    12. public void setdome04() {
    13. Set<Student> set = new HashSet<Student>();
    14. set.add(new Student(1, "张三", 18));
    15. set.add(new Student(2, "李四", 19));
    16. set.add(new Student(3, "李凝", 20));
    17. set.add(new Student(4, "王三", 21));
    18. set.add(new Student(4, "王三", 21));
    19. set.add(new Student(5,"二虎",26));
    20. for (Student student : set) {
    21. System.out.println(student);
    22. }
    23. }

    2.自定义排序

    --1. 较器通过构造函数传入比

    1. 1. 较器通过构造函数传入比
    2. TreeSet<Integer> tset = new TreeSet<Integer>(new Comparator<Integer>() {
    3. @Override
    4. public int compare(Integer o1, Integer o2) {
    5. // TODO Auto-generated method stub
    6. return o2 - o1;
    7. }
    8. });

    2. 2. 实现排序接口

    1. public class Student implements Comparable<Student>{
    2. private Integer sid;
    3. private String name;
    4. private int age;
    5. @Override
    6. public int compareTo(Student o) {
    7. // TODO Auto-generated method stub
    8. return o.getAge() - this.getAge();
    9. }
    10. }
    11. Student实体类
    12. package com.zking.test;
    13. public class Student implements Comparable<Student> {
    14. private Integer sid;
    15. private String sname;
    16. private int age;
    17. public Student(Integer sid, String sname, int age) {
    18. super();
    19. this.sid = sid;
    20. this.sname = sname;
    21. this.age = age;
    22. }
    23. public Integer getSid() {
    24. return sid;
    25. }
    26. public void setSid(Integer sid) {
    27. this.sid = sid;
    28. }
    29. public String getSname() {
    30. return sname;
    31. }
    32. public void setSname(String sname) {
    33. this.sname = sname;
    34. }
    35. public int getAge() {
    36. return age;
    37. }
    38. public void setAge(int age) {
    39. this.age = age;
    40. }
    41. @Override
    42. public int hashCode() {
    43. final int prime = 31;
    44. int result = 1;
    45. result = prime * result + age;
    46. result = prime * result + ((sid == null) ? 0 : sid.hashCode());
    47. result = prime * result + ((sname == null) ? 0 : sname.hashCode());
    48. return result;
    49. }
    50. @Override
    51. public boolean equals(Object obj) {
    52. if (this == obj)
    53. return true;
    54. if (obj == null)
    55. return false;
    56. if (getClass() != obj.getClass())
    57. return false;
    58. Student other = (Student) obj;
    59. if (age != other.age)
    60. return false;
    61. if (sid == null) {
    62. if (other.sid != null)
    63. return false;
    64. } else if (!sid.equals(other.sid))
    65. return false;
    66. if (sname == null) {
    67. if (other.sname != null)
    68. return false;
    69. } else if (!sname.equals(other.sname))
    70. return false;
    71. return true;
    72. }
    73. @Override
    74. public String toString() {
    75. return "Student [sid=" + sid + ", sname=" + sname + ", age=" + age + "]";
    76. }
    77. @Override
    78. public int compareTo(Student o) {
    79. if (this.getAge() - o.getAge() == 0) {
    80. return this.getSid() - o.getSid();
    81. }
    82. return this.getAge() - o.getAge();
    83. }
    84. }

    总结:

    set集合元素无放入顺序,且不可重复(注意:元素虽然无放入顺序,但是元素在Set中的位置是由该元素的HashCode决定的,其位置是固定的)。List支持for循环,也就是通过下标来遍历,也可以用迭代器,但是Set只能用迭代器,因为他无序,无法使用下标取值;Set:检索元素效率低,删除和插入效率高,插入和删除不会引起元素位置改变。

  • 相关阅读:
    Oracle中的NVL、NVL2、NULLIF、COALESCE函数详解
    PAT甲级真题1166
    砂锅的开锅与保养
    鸿蒙HarmonyOS实战-ArkUI动画(页面转场动画)
    32位增强型低功耗Cortex-M3单片机CH32F203C8T6
    LeetCode-63-不同路径Ⅱ-动态规划
    喜报丨迪捷软件入选浙江省2023年省级产业数字化服务商
    【定位问题】基于matlab chan算法、fang算法、taylor算法求解目标定位问题【含Matlab源码 2135期】
    proxychains DNS解析失败问题
    python+django+mysql校园网站毕业设计毕设开题报告
  • 原文地址:https://blog.csdn.net/weixin_67150631/article/details/125491767