40.java-单列集合Set(HashSet,LinkedHashSet,TreeSet)

1.Set集合特点

在这里插入图片描述

在这里插入图片描述

2.Set集合实现类

在这里插入图片描述

3. HashSet

3.1 底层原理

在这里插入图片描述

3.1.1 哈希表组成

在这里插入图片描述

3.1.2 哈希值

哈希值:对象的整数表现形式
在这里插入图片描述

在这里插入图片描述

3.1.3 对象的哈希值特点

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

3.2 数据添加元素的过程

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

3.3 HashSet的三个问题

1)
在这里插入图片描述
遍历时 是按照数组的索引从0开始读取数据的。当遇到数组索引中存在链表时,就会把数组当前索引里的链表存储的数据全部读取出来后,再继续遍历数组中的下一个索引。数组索引里的数据存储的是红黑树时,也会按照读取树的方法,把数据全部遍历出来后,再继续遍历下一个数组索引。
在这里插入图片描述
2)
在这里插入图片描述
存储方式不是单一的模式,由 数组,链表,红黑树共同组成。所以无法统一只用一个索引的方式去表述元素。

3)

在这里插入图片描述
用了2个方法去保证元素去重的。
HashCode 方法
equals 方法

3.4 实例:去除重复元素

在这里插入图片描述

package com.zjut.hashset;

import java.util.HashSet;

public class HashSetDemo1 {
    
    
    public static void main(String[] args) {
    
    
        /*
        * 需求:创建一个储存学生对象的集合,储存多个学生对象
        *       使用程序实现在控制台遍历该集合
        * 要求:学生对象的成员变量值相同,就认为是同一个对象
        * */

        //1.创建学生对象
        Student stu1 = new Student("zhangsan",23);
        Student stu2 = new Student("lisi",24);
        Student stu3 = new Student("wangwu",25);
        Student stu4 = new Student("zhangsan",23);

        //2.创建集合添加学生
        HashSet<Student> hs = new HashSet<>();
        //3.添加元素
        System.out.println(hs.add(stu1));
        System.out.println(hs.add(stu2));
        System.out.println(hs.add(stu3));
        System.out.println(hs.add(stu4));

        System.out.println(hs);
    }
}

package com.zjut.hashset;

import java.util.Objects;

public class Student {
    
    
    private String name;
    private int age;

    public Student() {
    
    
    }

    public Student(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
    
    
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
    
    
        return Objects.hash(name, age);
    }

    @Override
    public String toString() {
    
    
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

总结
当HashSet存储的是自定义类型时,需要重写 equals,hashCode 方法。不然,默认情况是按照对象的地址计算hash值,而不是按照对象的属性计算。就达不到去除重复元素的效果。

4. LinkedHashSet

在这里插入图片描述

遍历时,从头节点开始遍历,按照双链表的顺序遍历取出。
不是再和HashSet那种遍历方法:从数组的0 索引开始遍历,有重复的元素,然后一根一根链表的去查找。

5. TreeSet

5.1 特点

在这里插入图片描述

5.2 集合默认规则

在这里插入图片描述

字符串从前向后比较
在这里插入图片描述

5.3 例子

package com.zjut.TreeSet;

import java.util.Iterator;
import java.util.TreeSet;


public class TreeSetDemo1 {
    
    
    public static void main(String[] args) {
    
    
        TreeSet<Integer> ts = new TreeSet<>();

        ts.add(4);
        ts.add(5);
        ts.add(3);
        ts.add(2);
        ts.add(1);

        //打印集合
        System.out.println(ts);
        //遍历集合
        //迭代器
        Iterator<Integer> it = ts.iterator();
        while (it.hasNext()) {
    
    
            int i = it.next();
            System.out.println(i);
        }

        System.out.println("------------------------------------");
        //增强for
        for (int t : ts) {
    
    
            System.out.println(t);
        }
        System.out.println("------------------------------------");

        //lambda
        ts.forEach( integer -> System.out.println(integer));
    }
}

默认从大到小,排好顺序的
在这里插入图片描述

5.4 两种比较规则

对于自定义的数据类型,可以自定义比较规则。

TreeSet 底层是红黑树,不需要像HashSet一样重写equals,hashCode 方法,才能进行比较。

它有两种比较规则。
在这里插入图片描述

5.4.1 默认排序

在这里插入图片描述

package com.zjut.TreeSet;

import java.util.TreeSet;

public class TreeSetDemo2 {
    
    
    public static void main(String[] args) {
    
    
        /*
        * 排序方法:
        * 1. Student 实现Comparable接口,重写里面的抽象方法,再指定比较规则
        * */

        //1.创建学生对象
        Student stu1 = new Student("zhangsan",23);
        Student stu3 = new Student("wagnwu",25);
        Student stu2 = new Student("lisi",24);

        //2.创建集合对象
        TreeSet<Student>  ts =new TreeSet<>();
        //3.添加元素
        ts.add(stu1);
        ts.add(stu2);
        ts.add(stu3);
        //4.打印集合
        System.out.println(ts);
    }
}

package com.zjut.TreeSet;

import java.util.Objects;

public class Student implements Comparable<Student>{
    
    
    private String name;
    private int age;

    public Student() {
    
    
    }

    public Student(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
    
    
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Student student = (Student) o;
        return age == student.age && Objects.equals(name, student.name);
    }

    @Override
    public int hashCode() {
    
    
        return Objects.hash(name, age);
    }

    @Override
    public String toString() {
    
    
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    @Override
    //this:当前要添加的元素,
    //0:表示已经在红黑树中存在的元素

    //返回值:
    //负数:表示当前要添加的元素是小的,存红黑树的左边
    //正数:表示当前要添加的元素是大的,存红黑树的右边
    //0:表示当前要添加的元素已经存在,舍弃
    public int compareTo(Student o) {
    
    
        System.out.println("------------------");
        System.out.println("this:" + this);
        System.out.println("o:" + o);
        //指定排序规则
        //只看年龄:按照年龄的升序排列
        return  this.getAge() - o.getAge()  ;
    }
}

5.4.2 比较器排序

在这里插入图片描述

例子:
TreeSet对象排序练习
在这里插入图片描述

package com.zjut.TreeSet;

import java.util.Comparator;
import java.util.TreeSet;

public class TreeSetDemo3 {
    
    
    public static void main(String[] args) {
    
    
        /**
         * 需求:请自行选择比较器排序和自然排序两种方式:
         * 要求:存入四个字符串,“c" ,"ab", "df", "qwer"
         * 按照长度从短到长排序,如果长度一样则按照首字母排序。
         */
        //HashSet集合,字符串默认按照首字母排序,不会按照长度排序

        //1.创建集合 ,传递比较器 Comparator 比较规则
        TreeSet<String> ts = new TreeSet<>(new Comparator<String>() {
    
    
            @Override
            //s:要添加的元素
            //t1:表示已经在红黑树中存在的元素
            public int compare(String s, String t1) {
    
    
                int i = s.length() - t1.length();
                //如果一样,则按照默认的首字母排序
                i = i == 0 ? s.compareTo(t1) : i;
                return i;
            }
        });

/* 因为Comparator是函数式接口,所以可以使用 lambda 表达式写法
        TreeSet<String> ts = new TreeSet<>(( s,  t1) -> {
                int i = s.length() - t1.length();
                //如果一样,则按照默认的首字母排序
                i = i == 0 ? s.compareTo(t1) : i;
                return i;

        });
*/

        ts.add("c");
        ts.add("ab");
        ts.add("df");
        ts.add("qwer");

        System.out.println(ts);

    }
}

输出:
[ab, c, df, qwer]

5.5. TreeSet对象排序练习

在这里插入图片描述

package com.zjut.TreeSet;

import java.util.TreeSet;

public class TreeSetDemo4 {
    
    
    public static void main(String[] args) {
    
    

        /*TreeSet排序规则
        * 1.默认排序,自然排序
        * 2.比较器排序
        * 默认情况下,用第一种排序,如果第一种不能满足当前的需求,采用第二种方式
        * */

         //1.创建学生对象
        Student02 st1 = new Student02("zhangsan",23,90,98,89);
        Student02 st2 = new Student02("lisi",24,91,97,88);
        Student02 st3 = new Student02("wangwu",25,90,96,70);
        Student02 st4 = new Student02("zhaoliu",26,60,80,68);
        Student02 st5 = new Student02("qianqi",27,70,77,77);

        //2.创建集合
        //默认选择ArrayList
        //HashSet
        //TreeSet
        TreeSet<Student02> ts = new TreeSet<>() ;
        ts.add(st1);
        ts.add(st2);
        ts.add(st3);
        ts.add(st4);
        ts.add(st5);

        //System.out.println(ts);
        for (Student02 t : ts) {
    
    
            System.out.println(t);
        }

    }
}

package com.zjut.TreeSet;

public class Student02 implements Comparable<Student02> {
    
    
    private String name;
    private int age;
    private int chinese;
    private int math;
    private int english;

    public Student02() {
    
    
    }

    public Student02(String name, int age, int chinese, int math, int english) {
    
    
        this.name = name;
        this.age = age;
        this.chinese = chinese;
        this.math = math;
        this.english = english;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    public int getChinese() {
    
    
        return chinese;
    }

    public void setChinese(int chinese) {
    
    
        this.chinese = chinese;
    }

    public int getMath() {
    
    
        return math;
    }

    public void setMath(int math) {
    
    
        this.math = math;
    }

    public int getEnglish() {
    
    
        return english;
    }

    public void setEnglish(int english) {
    
    
        this.english = english;
    }

    @Override
    public String toString() {
    
    
        return "Student02{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", chinese=" + chinese +
                ", math=" + math +
                ", english=" + english +
                '}';
    }

    /*
     * 按照总分从高到底 输出到控制台
     * 如果总分一样,按照语文成绩排
     * 如果语文一样,按照数学成绩排
     * 如果数学成绩一样,按照英语成绩排
     * 如果英语成绩一样,按照年龄排
     * 如果年龄一样,按照姓名的首字母排
     * 如果都一样,认为是同一个学生,不存
     * */
    @Override
    public int compareTo(Student02 student02) {
    
    
        int sum1 = this.getChinese() + this.getEnglish() + this.getMath();
        int sum2 = student02.getChinese() + student02.getMath() + student02.getEnglish();

        //比较两者总分
        int i = sum1 - sum2;
        //如果总分一样,按照语文成绩排
        i = i == 0 ? this.getChinese() - student02.getChinese() : i;
        //如果语文一样,按照数学成绩排
        i = i == 0 ? this.getMath() - student02.getMath() : i;
        //如果数学成绩一样,按照英语成绩排,(可以省略,因为三门成绩总分一样,而语文,数学成绩一样,那英语成绩肯定一样)
        i = i == 0 ? this.getEnglish() - student02.getEnglish() : i;
        //如果英语成绩一样,按照年龄排
        i = i == 0 ? this.getAge() - student02.getAge() : i;
        //如果年龄一样,按照姓名的首字母排
        i = i == 0 ? this.getName().compareTo(student02.getName()): i;

        return i;
    }
}

在这里插入图片描述

5.6 TreeSet小结

5.6.1 TreeSet集合的特点?

在这里插入图片描述

5.6.2 TreeSet集合自定义排序规则有几种方式?

在这里插入图片描述

5.6.3 方法返回值得特点

在这里插入图片描述

6. 单列集合使用场景

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/u014217137/article/details/130302223