JavaSE——集合(三)Set(HashSet,LinkedHashSet,TreeSet)

哈希值
  • 概念
    哈希值是一个十进制的整数,由系统随机给出(就是对象的地址值,是一个逻辑地址,是模拟出来得到地址,不是数据实际存储的物理地址)
  • 使用
    Object类就提供了求哈希值的方法
public native int hashCode();

演示

package com.westmo1.demo4;
public class MyDemo2 {
    public static void main(String[] args) {
        MyDemo2 myDemo2 = new MyDemo2();
        System.out.println(myDemo2.hashCode());
        MyDemo2 myDemo21 = new MyDemo2();
        System.out.println(myDemo21.hashCode());
    }
}
  • String类演示
package com.westmo1.demo4;
public class MyDemo2 {
    public static void main(String[] args) {
        String abc = new String("abc");
        String abc1 = new String("abc");
        System.out.println(abc.hashCode());//96354
        System.out.println(abc1.hashCode());//96354
        System.out.println("重地".hashCode());//1179395
        System.out.println("通话".hashCode());//1179395
    }
}

1.HashSet

  • 概述

(1)底层数据结构是哈希表,元素唯一且无序。
①jdk1.8以前:哈希表=数组+链表
②jdk1.8以后:哈希表=数组+链表+红黑树
(2)数据结构:数组结构:对元素进行了分组(相同哈希值的元素在一组),链表/红黑树结构:将相同哈希值的元素连接到一起
JavaSE——集合(三)Set(HashSet,LinkedHashSet,TreeSet)_第1张图片
(3) 哈希冲突:两个元素不同,但是哈希值相同,就会发生哈希冲突

  • 案例演示
package com.westmo1.demo1;
import java.util.HashSet;
public class MyDemo1 {
    public static void main(String[] args) {
        HashSet strings = new HashSet<>();
        strings.add("123");
        strings.add("qewq");
        for (String string : strings) {
            System.out.println(string);
        }
    }
}
  • HashSet保证元素唯一性(以hashset.add(“重地”)为例)

首先add方法会调用hashCode方法来获取字符串"重地"的哈希码值,它的哈希码值是1179395,在集合中找有没有1179395这个哈希码值的元素:
(1)如果有(哈希冲突):"重地"就会调用equals方法和哈希码值相同的元素进行比较:
①返回为true:则两个元素相同,"重地"就不存储到集合中。
②返回为false:则存储到集合中(以链表/红黑数的形式链接到哈希码值相同的元素的后面)。
(2)如果没有:就将"重地"存储到集合中。
所以:HashSet保证元素唯一性是靠重写hashCode()和equals()方法来保证的,如果不重写则无法保证。

  • HashSet存储自定义对象保证元素唯一性
package com.westmo1.demo1;
import java.util.HashSet;
public class MyDemo2 {
    public static void main(String[] args) {
        Student student = new Student("张三", 13);
        Student student1 = new Student("张三", 13);
        Student student2 = new Student("李四", 15);
        Student student3 = new Student("李四", 15);
        Student student4 = new Student("王五", 18);
        HashSet students = new HashSet<>();
        students.add(student);
        students.add(student1);
        students.add(student2);
        students.add(student3);
        students.add(student4);
        for (Student student5 : students) {
            System.out.println(student5);
        }
    }
}
package com.westmo1.demo1;
import java.util.Objects;
public class Student {
    private String name;
    private int age;
    public Student(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Student)) return false;
        Student student = (Student) o;
        return age == student.age &&
                Objects.equals(name, student.name);
    }
    @Override
    public int hashCode() {
        return Objects.hash(name, age);
    }
}
  • HashSet存储自定义对象保证元素唯一性图解

JavaSE——集合(三)Set(HashSet,LinkedHashSet,TreeSet)_第2张图片

2.LinkedHashSet

  • 概述

底层数据结构是由链表和哈希表实现的,链表保证有序,哈希表保证元素唯一。

  • 案例演示
package com.westmo1.demo1;
import java.util.LinkedHashSet;
public class MyDemo3 {
    public static void main(String[] args) {
        LinkedHashSet integers = new LinkedHashSet<>();
        integers.add(300);
        integers.add(100);
        integers.add(400);
        integers.add(100);
        for (Integer integer : integers) {
            System.out.println(integer);
        }
    }
}

3.TreeSet

概述

TreeSet集合特点:元素唯一,并且可以对元素进行排序,
排序有两种方式:自然排序和使用比较器排序。

使用TreeSet集合进行元素的自然排序
  • 注意事项:采用空参构造,要求元素必须实现Comparable接口
  • 案例演示
package com.westmo1.demo1;
import java.util.TreeSet;
public class MyDemo4 {
    public static void main(String[] args) {
        TreeSet integers = new TreeSet<>();
        /*存储下列元素:  20 , 18 , 23 , 22 , 17 , 24, 19 , 18 , 24*/
        integers.add(20);
        integers.add(18);
        integers.add(23);
        integers.add(22);
        integers.add(17);
        integers.add(24);
        integers.add(19);
        integers.add(18);
        integers.add(24);
        for (Integer integer : integers) {
            System.out.println(integer);
        }
    }
}
  • 自然排序的原理

利用二叉树的数据结构,现存入一个树根,分两个叉,存储元素时,和树根比较,小的放在左边,大的放在右边,如果相等就不存储。

  • TreeSet存储自定义对象并遍历1
//按照年龄来排序,注意特殊情况
package com.westmo1.demo1;
public class Student1 implements Comparable{
    private String name;
    private int age;

    public Student1(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student1{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    @Override
    public int compareTo(Student1 o) {
        int num=this.age-o.age;
        int num1=this.name.compareTo(o.name);
        if (num==0) {
            num=num1;
        }
        return num;
    }
}
//从例中可以看出,TreeSet集合自然排序需要实现Compraable接口和重写compareTo方法。
package com.westmo1.demo1;
import java.util.TreeSet;
public class MyDemo5 {
    public static void main(String[] args) {
        Student1 student = new Student1("张三", 13);
        Student1 student1 = new Student1("小花", 10);
        Student1 student2 = new Student1("李四", 19);
        Student1 student3 = new Student1("小明", 17);
        Student1 student4 = new Student1("王五", 13);
        TreeSet student1s = new TreeSet<>();
        student1s.add(student);
        student1s.add(student1);
        student1s.add(student2);
        student1s.add(student3);
        student1s.add(student4);
        for (Student1 student11 : student1s) {
            System.out.println(student11);
        }
    }
}
  • TreeSet存储自定义对象并遍历2
//按照姓名的长度排序,注意名字长度相同时,年龄相同时的情况。
package com.westmo1.demo1;
import java.util.TreeSet;
public class MyDemo6 {
    public static void main(String[] args) {
        Student2 student = new Student2("张三话", 13);
        Student2 student1 = new Student2("小花阿叔", 10);
        Student2 student2 = new Student2("李四", 19);
        Student2 student3 = new Student2("小明的股数打", 17);
        Student2 student4 = new Student2("王五", 19);
        TreeSet student1s = new TreeSet<>();
        student1s.add(student);
        student1s.add(student1);
        student1s.add(student2);
        student1s.add(student3);
        student1s.add(student4);
        for (Student2 student11 : student1s) {
            System.out.println(student11);
        }
    }
}
package com.westmo1.demo1;
public class Student2 implements Comparable{
    private String name;
    private int age;
    public Student2(String name, int age) {
        this.name = name;
        this.age = age;
    }
    @Override
    public String toString() {
        return "Student1{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
    @Override
    public int compareTo(Student2 o) {
        int num2=this.name.length()-o.name.length();//先比较名字长度
        int num=this.name.compareTo(o.name);//再比较名字的内容
        int num1=this.age-o.age;//比较年龄
        if (num2==0) {
            num2=num;
        }
        if (num==0) {
            num2=num1;
        }
        return num2;
    }
}
使用TreeSet集合进行元素的自然排序(自定义比较器)
  • 注意事项

自定义的比较器要实现Comparator接口,重写Compare方法。在创建TreeSet对象的时候,就传递一个比较器对象。

  • 案例演示
package com.westmo1.demo1;
import java.util.Comparator;
import java.util.TreeSet;
public class MyDemo7 {
    public static void main(String[] args) {
        Student3 student1 = new Student3("小明",15);
        Student3 student2 = new Student3("小话",19);
        Student3 student3 = new Student3("小明挂个人",10);
        Student3 student4 = new Student3("李海华",15);
        NameComparable nameComparable = new NameComparable();//姓名比较器
        AgeComparable ageComparable = new AgeComparable();//年龄比较器
        TreeSet student3s = new TreeSet(nameComparable);//传递姓名比较器对象,也可以用匿名内部类来实现
        student3s.add(student1);
        student3s.add(student2);
        student3s.add(student3);
        student3s.add(student4);
        for (Student3 student31 : student3s) {
            System.out.println(student31);
        }
    }
    static class Student3{
        private String name;
        private int age;
        public Student3(String name, int age) {
            this.name = name;
            this.age = age;
        }
        @Override
        public String toString() {
            return "Student3{" +
                    "name='" + name + '\'' +
                    ", age=" + age +
                    '}';
        }
    }
    //自定义年龄比较器对象
    static class AgeComparable implements Comparator {
        @Override
        public int compare(Object o1, Object o2) {
            Student3 o11 = (Student3) o1;
            Student3 o21 = (Student3) o2;
            int num=o11.age-o21.age;
            int num1=o11.name.compareTo(o21.name);
            if (num==0) {
                num=num1;
            }
            return num;
        }
    }
    //自定义姓名比较器对象
    static class NameComparable implements Comparator{
        @Override
        public int compare(Object o1, Object o2) {
            Student3 o11 = (Student3) o1;
            Student3 o21 = (Student3) o2;
            int num=o11.name.length()-o21.name.length();
            int num1=o11.name.compareTo(o21.name);
            int num2=o11.age-o21.age;
            if (num==0) {
                num=num1;
            }
            if (num1==0) {
                num=num2;
            }
            return num;
        }
    }
}
练习1(产生10个1-20之间的随机数要求随机数不能重复)
package com.westmo1.demo1;
import java.util.TreeSet;
public class MyDemo8 {
    public static void main(String[] args) {
        TreeSet integers = new TreeSet<>();
        while(integers.size()<10) {
            int random = (int) (Math.random()*20+1);
            integers.add(random);
        }
        for (Integer integer : integers) {
            System.out.println(integer);
        }
    }
}
练习2(键盘输入学生信息按照总分排序后输出,使用比较器进行)
package com.westmo1.demo1;
import java.util.Comparator;
import java.util.Scanner;
import java.util.TreeSet;
public class MyDemo9 {
    public static void main(String[] args) {
    //使用匿名内部类来传参,不需要再创建一个类来实现Comparator接口这么麻烦。
        TreeSet student4s = new TreeSet(new Comparator() {
            @Override
            public int compare(Student4 o1, Student4 o2) {
                int num=o1.getTotal()-o2.getTotal();
                int num1=num==0?o1.name.compareTo(o2.name):num;
                return -num1;
            }
        });
        Scanner scanner = new Scanner(System.in);
        for (int i = 0; i < 3; i++) {
            System.out.println("输入第" + i + "个学生的信息");
            String name = scanner.next();
            int math = scanner.nextInt();
            int chinese = scanner.nextInt();
            int english = scanner.nextInt();
            Student4 student4 = new Student4(name, math, chinese, english);
            student4s.add(student4);
        }
        for (Student4 student4 : student4s) {
            System.out.println(student4);
        }
    }
    static class Student4 {
        private String name;
        private int math;
        private int chinese;
        private int english;

        public Student4(String name, int math, int chinese, int english) {
            this.name = name;
            this.math = math;
            this.chinese = chinese;
            this.english = english;
        }
        @Override
        public String toString() {
            return "Student4{" +
                    "姓名='" + name +
                    ", 数学=" + math +
                    ", 语文=" + chinese +
                    ", 英语=" + english +",总分="+getTotal()+
                    '}';
        }
        public int getTotal(){
            return math+chinese+english;
        }
    }
}

你可能感兴趣的:(JavaSE,javase)