zoukankan      html  css  js  c++  java
  • Java学习之路(八):Set

    Set集合概述以及特点:

    • set 是一个不包含重复元素的collection
    • set只是一个接口,一般使用它的子类HashSet,LinkedHashSet,TreeSet

    HashSet

    • 此类是Set接口的实现类,有哈希表支持
    • 它不保证set的迭代顺序,特别是不保证顺序的恒久不变
    • 此类允许使用null元素

    我们一般使用HashSet来去重:

    • 我们需要重写累的hashCode()和equals()方法

    HashSet去重的依据:

      首先会比较hashCode(),如果不一样则存进去,如果一样的话,调用equals()方法进行比较,如果返回True就不存储,false存储

    面试题:为什么自动生成hashCode的时候有个31的数?

    31是一个质数,质数是能被1和自己本身整除的数,没有公约数
    
    31刚刚好,既不大也不小
    
    31这个数好算,2的五次方-1,相当于向左移5位-1
    答案

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

    package l1;
    
    import java.util.HashSet;
    import java.util.Random;
    import java.util.Set;
    
    public class Demo01 {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
    
            Set<Integer> set = new HashSet<Integer>();
            Random rd = new Random();
            while(set.size()!=10){
                int r = rd.nextInt(21);  //生成1-20之间的随机数
                if(r!=0){
                    set.add(r);
                }
            }
            System.out.println(set);
            
            
        }
    
    }

     案例:从键盘读取一行输入,去掉重复字符并打印

    package l2;
    
    import java.util.HashSet;
    import java.util.Scanner;
    import java.util.Set;
    
    public class Demo2 {
    
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            System.out.println("请输入一行内容");
            String line = sc.nextLine();
            
            //将字符串转化为字符数组
            char[] ch = line.toCharArray();
            
            Set<Character> set = new HashSet<Character>();
            for(char a:ch){
                set.add(a);
            }
            
            System.out.println(set);
        }
    
    }

     案例:使用HashSet()过滤List集合中的重复的元素

    package l3;
    
    import java.util.ArrayList;
    import java.util.HashSet;
    import java.util.List;
    import java.util.Set;
    
    public class Demo3 {
    
        public static void main(String[] args) {
            List<String> li = new ArrayList<String>();
            li.add("A");
            li.add("B");
            li.add("A");
            li.add("A");
            Set<String> set = new HashSet<String>();
            set.addAll(li);
            System.out.println(set);
    
        }
    
    }

     LinkedHashSet的概述和使用

    • LinkedHashSet是一个具有可预知迭代顺序的Set接口
    • 内部实现是使用哈希表和链接列表
    • LinkedHashSet的特点是可以保证怎么存就怎么取
    • LinkedHashSet是set集合中唯一一个能保证怎么存就怎么取的集合对象
    • LinkedHashSet是HashSet的子类,所以也是保证元素唯一的,实现原理和HashSet一样

    TreeSet的概述和使用 

    • TreeSet是一个可以用于排序的集合、
    • TreeSet给予TreeMap的NavigableSet实现
    • TreeSet的排序方法有两种:
      • 使用元素的自然顺序Comparable对元素进行排序
      • 使用构造方法的Comparator进行排序

    使用TreeSet 存储自定义对象:

    注意:使用TreeSet存储自定义对象是会出现异常:xxxx cannot be cast to java.lang.Comparable

    • 如果想用TreeSet存储自定义对象,这个对象必须要实现Comparable接口
    • 此接口强行堆实现它的每个类的对象进行排序
    • 这种排序被称为自然排序,类的compareTo方法被成为它的自然比较方法
    • 当compareTo方法返回0的时候,集合只会保留一个元素
    • 当compareTo方法返回正数的时候,集合怎么存就怎么取
    • 当compareTo方法返回负数的时候,集合会倒序存储

    TreeSet存储自定义对象并遍历

    package lesson0001;
    
    import java.util.Set;
    import java.util.TreeSet;
    
    public class Demo1 {
    
        public static void main(String[] args) {
    
            Set<Student> set = new TreeSet<Student>();
            set.add(new Student(1,"n1"));
            set.add(new Student(2,"n2"));
            set.add(new Student(3,"n3"));
            for(Student std:set){
                System.out.println(std);
            }
        }
    
    }
    
    class Student implements Comparable{
        private int age;
        private String name;
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        @Override
        public String toString() {
            return "Student [age=" + age + ", name=" + name + "]";
        }
        public Student() {
            super();
            // TODO Auto-generated constructor stub
        }
        public Student(int age, String name) {
            super();
            this.age = age;
            this.name = name;
        }
        @Override
        public int compareTo(Object arg0) {
            return 1;
        }
    }

    以上是最简单的一个例子,然后呢,我们现在需要实现:

      TreeSet存储自定义对象并且遍历,而且要按照姓名长度,字母,年龄顺序排序

    • 通过比较字符串的compareTo比较大小
    • 排序按照unicode码的大小进行排序
    • 防止名字相同,但年龄不同的Bug
    package lesson0002;
    
    import java.util.Set;
    import java.util.TreeSet;
    
    public class Demo1 {
    
        public static void main(String[] args) {
    
            Set<Student> set = new TreeSet<Student>();
            set.add(new Student(1,"aaaa"));
            set.add(new Student(5,"aaaa"));
            set.add(new Student(2,"aaaa"));
            set.add(new Student(1,"aaa"));
            set.add(new Student(1,"aa"));
            for(Student std:set){
                System.out.println(std);
            }
            
        }
    
    }
    main代码
    package lesson0002;
    
    public class Student implements Comparable<Student> {
        private int age;
        private String name;
        public int getAge() {
            return age;
        }
        public void setAge(int age) {
            this.age = age;
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        
    
        public Student(int age, String name) {
            super();
            this.age = age;
            this.name = name;
        }
        public Student() {
            super();
            // TODO Auto-generated constructor stub
        }
        @Override
        public int compareTo(Student o) {
            int length = this.name.length() - o.name.length();
            int num = length == 0?this.name.compareTo(o.name):length;
            return num == 0?this.age-o.age:num;
        }
        @Override
        public String toString() {
            return "Student [age=" + age + ", name=" + name + "]";
        }
        
    
        
    }
    Student类

    TreeSet除了这种自定义排序意外还可以定义一种自定义排序:比较器(Comparator)

    package lesson0003;
    
    import java.util.Comparator;
    import java.util.Set;
    import java.util.TreeSet;
    
    //比较器排序
    
    
    public class Demo1 {
    
        public static void main(String[] args) {
    
            Set<String> set = new TreeSet<String>(new Comparator<String>() {
    
                @Override
                public int compare(String o1, String o2) {
                    
                    int num = o1.compareTo(o2);//默认的从小到大
                    num = num==0?1:num;  //如果相同返回1,即保存同名的元素
                    return num;
                }
            });
            
            
            set.add("aaa");
            set.add("bbb");
            set.add("ccc");
            set.add("aaa");
            set.add("aa");
            for(String s:set){
                System.out.println(s);
            }
        }
    
    }

    TreeSet的总结

    TreeSet是用来排序的,可以指定一个顺序,对象存入之后会按照指定的顺序排序

    TreeSet的排序方式有两种:

    • 自然排序
    • 比较器顺序

    自然顺序:

    1. TreeSet类的add方法会把存入的对象提升为Comparable类型
    2. 调用对象的compareTo方法进行比较
    3. 根据compareTo方法返回的结果进行一个存储

    比较器顺序:

    1. 创建TreeSet的时候可以定制一个Comparator
    2. 如果传入了Comparator的子类对象,那么TreeSet就会按照比较器的规则比较
    3. add方法内部会调用Comparator接口中的compare方法排序
    4. 调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数

    自然排序和比较器排序的区别:

    • TreeSet构造函数什么都不传,默认按照类中的Comparable的排序
    • TreeSet如果传入Comparator,就优先按照Comparator(即,比较器排序要优先)

    练习题案例:

    1.在一个集合中存储了无序并且重复的字符串,让其有序,而且不能去除重复

    我上面例子中,比较器排序的那个例子就是
    答案

    2.从键盘输入多个整数,直到输入quit时结束输入。把所有输入的整数倒叙排列打印

    package lesson0004;
    
    import java.util.Comparator;
    import java.util.Scanner;
    import java.util.Set;
    import java.util.TreeSet;
    
    public class Demo01 {
    
        public static void main(String[] args) {
            
            Set<Integer> set = new TreeSet<Integer>(new Comparator<Integer>() {
    
                @Override
                public int compare(Integer o1, Integer o2) {
                    // TODO Auto-generated method stub
                    return (o2-o1)==0?1:(o2-o1);
    //                return o2-o1;
                }
            });
            
            Scanner sc = new Scanner(System.in);
            while(true){
                String str = sc.nextLine();
                if("quit".equals(str)){
                    break;
                }else{
                    set.add(Integer.parseInt(str));
                }
            }
            for(Integer i:set){
                System.out.println(i);
            }
    
            
            
        }
    
    }
    答案

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

    package lesson0005;
    
    import java.util.Comparator;
    import java.util.Scanner;
    import java.util.Set;
    import java.util.TreeSet;
    
    public class Demo1 {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            
            Set<Student> set = new TreeSet<Student>();
            
            Scanner sc = new Scanner(System.in);
            while(true){
                System.out.println("请按照格式输入学生信息(学生名:年龄:成绩)");
                String line = sc.nextLine();
                if("quit".equals(line)){
                    break;
                }else{
                    String name = line.split(":")[0];
                    int age = Integer.parseInt(line.split(":")[1]);
                    int score = Integer.parseInt(line.split(":")[2]);
                    set.add(new Student(name,age,score));
                }
            }
            for(Student std:set){
                System.out.println(std);
            }
            
            
        }
    
    }
    答案:main
    package lesson0005;
    
    public class Student implements Comparable<Student> {
    
        private String name;
        private int age;
        private int score;
        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 getScore() {
            return score;
        }
        public void setScore(int score) {
            this.score = score;
        }
        @Override
        public String toString() {
            return "Student [name=" + name + ", age=" + age + ", score=" + score + "]";
        }
        public Student() {
            super();
        }
        public Student(String name, int age, int score) {
            super();
            this.name = name;
            this.age = age;
            this.score = score;
        }
        @Override
        public int compareTo(Student o) {
            int num = o.score - this.score;
            num =  num==0?this.name.compareTo(o.name):num;
            num =  num==0?(this.age-o.age):num;
            return num==0?1:num;
        }
        
        
        
    }
    答案:Student类
  • 相关阅读:
    冲刺阶段第三天
    冲刺阶段第二天
    冲刺阶段第一天
    工作项估计
    学习进度条(7-9周)
    团队计划会议01
    第一次冲刺阶段(一)
    软件项目团队报告
    团队项目会议第一次
    团队开发项目需求简介
  • 原文地址:https://www.cnblogs.com/smiling-crying/p/9375244.html
Copyright © 2011-2022 走看看