Set集合
- 1.Set集合特点
- 2.Set集合实现类
- 3. HashSet
- 3.1 底层原理
- 3.1.1 哈希表组成
- 3.1.2 哈希值
- 3.1.3 对象的哈希值特点
- 3.2 数据添加元素的过程
- 3.3 HashSet的三个问题
- 3.4 实例:去除重复元素
- 4. LinkedHashSet
- 5. TreeSet
- 5.1 特点
- 5.2 集合默认规则
- 5.3 例子
- 5.4 两种比较规则
- 5.4.1 默认排序
- 5.4.2 比较器排序
- 5.5. TreeSet对象排序练习
- 5.6 TreeSet小结
- 5.6.1 TreeSet集合的特点?
- 5.6.2 TreeSet集合自定义排序规则有几种方式?
- 5.6.3 方法返回值得特点
- 6. 单列集合使用场景
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);
}
}
输出:
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;
}
}