Collection-set

1、set集合的概述

一个不包含重复元素的 collection。

  • 案例演示:无需和唯一
public class MyTest {
    public static void main(String[] args) {
        HashSet<String> hashSet = new HashSet<>();
        hashSet.add("张三");
        hashSet.add("李四");
        hashSet.add("王五");
        hashSet.add("张三");
        hashSet.add("李四");
        for (String s : hashSet) {
            System.out.println(s);
        }
    }
}

结果为:
在这里插入图片描述

2、HashSet

HashSet底层的数据结构是哈希表,HashSet不是线程安全的,集合元素可以是null。
哈希表:是一个元素为链表的数组,综合了数组和链表的优点(JDK1.7:数组+链表,JDK1.8优化后:数组+链表+二叉树 )

2.1、HashSet保证元素的唯一性

当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCOde()方法来得到该对象的hashCode值,然后根据hashCode值决定改对象在hashSet中存储位置。

hashSet集合判断两个元素相等的标准:
两个对象通过hashCode()方法比较相等,并且两个对象的equals()方法返回值也相等。

结论:HashSet保证元素唯一性是靠元素重写hashCode()和equals()方法来保证的,如果不重写则无法保证。

  • hashCode()和equals()方法重写代码
public class MyTest2 {
    public static void main(String[] args) {
        HashSet<Student> hashSet = new HashSet<>();
        Student s1 = new Student("张三", 26);
        Student s2 = new Student("李四", 26);
        Student s3 = new Student("王五", 26);
        Student s4 = new Student("张三", 26);
        Student s5 = new Student("张三", 26);
        Student s6 = new Student("张三", 26);
        hashSet.add(s1);
        hashSet.add(s2);
        hashSet.add(s3);
        hashSet.add(s4);
        hashSet.add(s5);
        hashSet.add(s6);

        for (Student student : hashSet) {
            System.out.println(student.getName()+"=="+student.getAge());
        }

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

    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 int hashCode() {
        //合理的重写hashCode()方法,可以减少碰撞次数,提高性能降低性能
        //因为成员变量值影响了哈希值,所以将成员变量值相加即可
        //return this.name.hashCode()+this.age;
        //但是会存在下面问题
        /*s1.name.hashCode()=40,age=30
        s2.name.hashCode()=20,age=50
        虽然成员变量不同,但是成员变量值相加下来相同。
        所以我们为了区分,将他们随便乘一个整数
        */
        return this.name.hashCode()+this.age*15;
    }

    @Override
    public boolean equals(Object obj) {
        if (this==obj){
            return true;
        }
        if (!(obj instanceof Student)){
            return false;
        }
        Student student= (Student) obj;
        return this.name.equals(student.name) && this.age == student.age;
    }
}

3、LinkedHashSet

元素有序,且唯一。
LinkedHashSet的概述:LinkedHashSet数据结构底层是两个链表和哈希表,元素唯一且有序。链表保证有序,哈希表保证唯一。

4、TreeSet

TreeSet集合的概述底层数据结构是二叉树,
TreeSet集合的特点:元素唯一,并且可以对元素进行排序。
排序方式

  • a、自然排序
  • b、使用比较器排序
    注意:使用TreeSet集合进行自然排序时,要求这个元素必须实现Comparable接口,否则无法进行排序
    元素唯一性:靠comparTo方法的返回值来确定,如果返回0,表示两个元素相等,则不重复存储。
  • 案例演示:存储Integer元素并遍历
public class MyTest3 {
    public static void main(String[] args) {
        TreeSet<Integer> set = new TreeSet<>();
        set.add(20);
        set.add(18);
        set.add(23);
        set.add(22);
        set.add(17);
        set.add(24);
        set.add(19);
        set.add(18);
        set.add(24);

        for (Integer integer : set) {
            System.out.println(integer);
        }
    }
}

4.1保证元素唯一和自然排序的原理

二叉树的数据结构存储数据,先存入一个树根,分两个叉,存储元素时,跟树根比较,小的放左边,大的放右边,如果想等就不存储,取的时候按照左中右的顺序来取。
在这里插入图片描述

4.2、TreeSet存储自定义对象并遍历练习1

  • 按照年龄进行排序
    年龄就是主要条件,姓名就是次要条件
public class MyTest4 {
    public static void main(String[] args) {
        //根据年龄进行排序,年龄相同再比较姓名
        TreeSet<Student> treeSet = new TreeSet<>();
        treeSet.add(new Student("乔丹",40));
        treeSet.add(new Student("科比",38));
        treeSet.add(new Student("詹姆斯",30));
        treeSet.add(new Student("姚明",33));
        treeSet.add(new Student("易建联",23));
        treeSet.add(new Student("王治郅",36));
        treeSet.add(new Student("王仕鹏",27));
        treeSet.add(new Student("孙悦",29));
        treeSet.add(new Student("姚明1",33));
        treeSet.add(new Student("易建联1",23));
        treeSet.add(new Student("王治郅1",36));
        for (Student student : treeSet) {
            System.out.println(student);
        }
    }
}

重写compareTo()方法

@Override
    public int compareTo(Student o) {
        int num = this.age - o.age;//先比较年龄
        //年龄相同再比较姓名
        /*if (num==0){
            boolean equals = this.name.equals(o.name);
            if (equals){
                num=0;
            }
        }
        return num;*/
        //代码优化
        int num2=(num==0)?this.name.compareTo(o.name):num;
        return num2;

4.3、TreeSet存储自定义对象并遍历练习2

  • 按照姓名的长度进行排序
    条件:主要是姓名的长度,然后是姓名,然后是年龄
public class MyTest5 {
    public static void main(String[] args) {
        TreeSet<Student> treeSet = new TreeSet<>();
        treeSet.add(new Student("迈克尔.乔丹",40));
        treeSet.add(new Student("科比.布莱恩特",38));
        treeSet.add(new Student("詹姆斯",30));
        treeSet.add(new Student("姚明",33));
        treeSet.add(new Student("里奥梅西",23));
        treeSet.add(new Student("王治郅",36));
        treeSet.add(new Student("王仕鹏",30));
        for (Student student : treeSet) {
            System.out.println(student);
        }
    }
}
public int compareTo(Student o) {
        //先比较姓名长度
        int num = this.name.length() - o.name.length();
        //姓名长度相同再比较年龄
        int num1=(num==0)?this.age - o.age:num;
        //年龄相同再比较姓名
        int num2=(num1==0)?this.name.compareTo(o.name):num;

        return num2;

4、比较器排序的原理

比较器排序:采用的是有参构造方法,构造方法中传入一个比较器(Comparetor 接口),需重写这个接口中的compare()方法,根据这个方法返回的 正 负 0来决定元素的排序。

  • TreeSet(Comparator<? super E> comparator)
    构造一个新的空 TreeSet,它根据指定比较器进行排序。
public class MyTest6 {
    public static void main(String[] args) {
        //根据年龄进行排序,年龄相同再比较姓名
        TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() {
            @Override
            public int compare(Student s1, Student s2) {
                int num = s1.getAge() - s2.getAge();
                int num1=(num==0)?s1.getName().compareTo(s2.getName()):num;
                return num1;
            }
        });
        treeSet.add(new Student("乔丹",40));
        treeSet.add(new Student("科比",38));
        treeSet.add(new Student("詹姆斯",30));
        treeSet.add(new Student("姚明",33));
        treeSet.add(new Student("易建联",23));
        treeSet.add(new Student("王治郅",36));
        treeSet.add(new Student("王仕鹏",27));
        treeSet.add(new Student("孙悦",29));
        treeSet.add(new Student("姚明1",33));
        treeSet.add(new Student("易建联1",23));
        treeSet.add(new Student("王治郅1",36));

        for (Student student : treeSet) {
            System.out.println(student);
        }
    }
}

5、案例:产生10个1-20之间的随机数要求随机数不能重复

需求:编写一个程序,获取10个1至20的随机数,要求随机数不能重复。
并把最终的随机数输出到控制台。
选HashSet 可以不重复
选TreeSet 不重复还可以排序
分析:
a: 定义一个HashSet集合
b: 产生随机数,把随机数添加到集合中
c: 判断集合的长度,使用while循环实现

public class MyTest7 {
    public static void main(String[] args) {
        HashSet<Integer> hashSet = new HashSet<>();
        Random random = new Random();
        while (hashSet.size()<10){
            hashSet.add(random.nextInt(20)+1);
        }
        System.out.println(hashSet);
    }
}

6、键盘录入学生信息按照总分排序后输出在控制台

需求:键盘录入3个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台。
步骤:
a: 自定义一个学生类
b: 创建一个TreeSet集合对象(使用比较器进行排序)
c: 键盘录入学生的数据,然后把学生的数据封装成一个学生对象,把学生对象添加到集合中
d: 遍历集合

public class MyTest8 {
    public static void main(String[] args) {
        TreeSet<Students> treeSet = new TreeSet<>(new Comparator<Students>() {
            @Override
            public int compare(Students s1, Students s2) {
                double num = s1.getTotleScore()-s2.getTotleScore();
                double num1=num==0?s1.getName().compareTo(s2.getName()):num;
                return (int) num1;
            }
        });
        for (int i = 1; i <= 3; i++) {
            Scanner scanner = new Scanner(System.in);
            System.out.println("请输入第"+i+"个学生姓名");
            Students stu = new Students();
            String name = scanner.nextLine();
            stu.setName(name);
            System.out.println("请输入第"+i+"个学生语文成绩");
            double yw = scanner.nextDouble();
            stu.setChineseScore(yw);
            System.out.println("请输入第"+i+"个学生数学成绩");
            double sx = scanner.nextDouble();
            stu.setMathScore(sx);
            System.out.println("请输入第"+i+"个学生英语成绩");
            double yy = scanner.nextDouble();
            stu.setEnglishScore(yy);
            treeSet.add(stu);
        }
        System.out.println("序号\t姓名\t语文成绩\t数学成绩\t英语成绩\t总分");
        int i =1;
        for (Students students : treeSet) {
            System.out.println((i++)+"\t"+students.getName()+"\t\t"+students.getChineseScore()+"\t\t"+students.getMathScore()+"\t\t"+students.getEnglishScore()+"\t\t"+students.getTotleScore());
        }
    }
}
public class Students {
    private String name;
    private double ChineseScore;
    private double MathScore;
    private double EnglishScore;

    public String getName() {
        return name;
    }

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

    public double getChineseScore() {
        return ChineseScore;
    }

    public void setChineseScore(double chineseScore) {
        ChineseScore = chineseScore;
    }

    public double getMathScore() {
        return MathScore;
    }

    public void setMathScore(double mathScore) {
        MathScore = mathScore;
    }

    public double getEnglishScore() {
        return EnglishScore;
    }

    public void setEnglishScore(double englishScore) {
        EnglishScore = englishScore;
    }

    //获取总分
    public double getTotleScore(){
        return this.ChineseScore+MathScore+EnglishScore;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值