Day14

作者: 拼搏男孩 | 来源:发表于2019-12-07 17:44 被阅读0次

    一. ArrayList嵌套

    1. 定义

      • 在集合中存放集合,和二维数组类似
    2. 演示

      public static void main(String[] args) {
       //集合中的元素还是集合
       ArrayList<ArrayList<Student>> school = new ArrayList<>();
       
       ArrayList<Student> clas1 = new ArrayList<>();
       clas1.add(new Student("小红",18));
       clas1.add(new Student("小明", 20));
       
       school.add(clas1);
       
       ArrayList<Student> clas2 = new ArrayList<>();
       clas2.add(new Student("小张",18));
       clas2.add(new Student("小李", 20));
       school.add(clas2);
       
       ArrayList<Student> clas3 = new ArrayList<>();
       clas3.add(new Student("tom",18));
       clas3.add(new Student("jack", 20));
       school.add(clas3);
       
       System.out.println(school);
      }
      
    3. 测试题

      • 需求: 先有一家宾馆,宾馆中有多个房间, 每个房间有数量不等客人, 使用集合嵌套的形式模拟并打印所有人的信息

    二. Set集合

    1. 定义

      • Set集合存数的元素是无序的, 而且不允许储存重复的元素, 每当有新的元素存入的时候,Set集合会先去过滤, 如果发现和集合中现有元素出现重复, 就不在允许添加
    2. 应用场景

      • 当我们不想让集合中出现重复的元素时,使用Set集合
      • 当我们需要排除重复数据时,使用Set集合
    3. 演示

      public static void main(String[] args) {
       //集合中的元素还是集合
       HashSet<Student> s = new HashSet<>();
       
       Student student = new Student("小红", 18);
       Student student2 = new Student("小红", 18);
      
       s.add(student);
       s.add(student2);
       
       Iterator<Student> it = s.iterator();
       while (it.hasNext()) {
           Student student3 = it.next();
           System.out.println(student3);
       }
      }
      

    三. HashSet

    1. 定义

      • HashSet集合中的元素是通过hash值来比较是否相同
      • 集合通过元素的hashCode和equals方法来比较两个元素是否相同, 不同就存入, 相同不存入
      • 元素存入的位置未知,和存入的顺序无关
    2. 存储原理

      • HashSet最后还是存入数组中, 只是根据元素的Hash值来确定存入的角标位置
        • 元素的hash值 ^ (元素的hash值 >>> 16) & (数组的长度-1)
      • HashSet中不是直接存入我们给定的元素, 而是用集合中的一个内部类封装我们存入的元素,所以当我们存入null的时候,不会因为和数组中角标位上默认值null起冲突
      • 如果两个不同的元素根据不同的Hash值计算出了同一个角标值,那么都能存进去
    3. 构造方法

      • HashSet() 构造出一个新的集合, 底层数组默认的初始容量是16(扩容一倍),加载因子是0.75
        • 加载因子: 集合中的数组可用的
        • 角标值得可选范围越小,计算出重复角标值得概率就越高
      • HashSet(Collection<? extends E> c) 构造一个包含指定collection中元素的新set
    4. 常用方法

      • boolean add( E e) 如果此set集合中尚未包含指定元素,则添加指定元素
      • boolean remove(Object o) 移除某个元素 []
      • int size() 获取集合的长度
    5. 演示

      • 需求: 去除ArrayList集合中的重复元素
      public static void main(String[] args) {
      
       ArrayList<String> al = new ArrayList<>();
       al.add("a");
       al.add("s");
       al.add("x");
       al.add("a");
       al.add("s");
       
       HashSet<String> hs = new HashSet<>(al);
       System.out.println(hs);
      }
      
    6. 测试题

      • 需求: 创建Student类, 定义name和age属性, 创建多个对象(有属性重复的对象)存入ArrayList集合中, 然后对集合中的元素去重

    四. HashSet集合中元素保证唯一性

    1. 原理解析

      • HashMap是通过调用元素的hashCode方法来比较两个元素是否形同的,所有如果要保证引用数据类型逻辑上的唯一性,就必须重写hashCode方法和equals方法
      • 演示
      public int hashCode() {
       final int prime = 31;
       int result = 1;
       result = prime * result + age;
       result = prime * result + ((name == null) ? 0 : name.hashCode());
       return result;
      }
      
      • prime = 31 的原因
        • 别人选的, 没有原因
        • 是质数, 和别的值计算得出的数重复的概率低
        • 大小适中, 不会出现太大导致结果无法使用的问题
        • 便于计算 2<<5 -1
    2. 引用数据类型除重

      • 重写hashCode和equals方法,自定义比较内容
    3. 测试题

      • 需求: 编写程序, 获取10个1到20的随机数, 要求随机数不能重复, 打印结果
      public static void main(String[] args) {
      
       Random random = new Random();
       
       HashSet<Integer> hashSet = new HashSet<>();
       
       while(hashSet.size()<10){
           int num = random.nextInt(20)+1;
           hashSet.add(num);
       }
       System.out.println(hashSet);
      }
      
    4. 测试题

      • 需求: 从键盘录入一行数据, 去掉其中重复的字符,打印结果
      public static void main(String[] args) {
       Scanner sc = new Scanner(System.in);
      
       System.out.println("请输入一行字符串:");
       String line = sc.nextLine();                    //将键盘录入的字符串存储在line中
       char[] arr = line.toCharArray();                //将字符串转换成字符数组
       HashSet<Character> hs = new HashSet<>();        //创建HashSet集合对象
      
       for (int i = 0; i < arr.length; i++) {
           hs.add(arr[i]);
       }
      
       Iterator<Character> it = hs.iterator();
       while (it.hasNext()) {
           System.out.print(it.next());
       }
       
       sc.close();
      }
      
    5. 测试题

      • 产生10个随机的字符串, 要求不能重复(字符串中的字符取值在 'a' 到 'z' , 'A' 到 'Z' ,'0' 到 '9'),字符串的长度1-20

    五. LinkedHashSet

    1. 定义

      • 兼顾了linked的有序性和HashSet的元素唯一性
    2. 演示

      public static void main(String[] args) {
      
       HashSet<String> hashSet = new HashSet<>();
       
       hashSet.add("b");
       hashSet.add("c");
       hashSet.add("a");
       hashSet.add("d");
       
       System.out.println(hashSet); //结果 : [a, b, c, d]
       
       LinkedHashSet<String> lhs = new LinkedHashSet<>();
       lhs.add("b");
       lhs.add("c");
       lhs.add("a");
       lhs.add("d");
       System.out.println(lhs); //结果: [b, c, a, d]
      }
      

    六. TreeSet集合

    1. 定义

      • TreeSet是一种顺序的集合, 记住, 这里的顺序是指集合中的元素有顺序, 她是通过比较元素的大小来存放的, 大的存右边,小的存左边
      • 存入的元素必须实现Comparable接口,并且重写comparTo方法
      • 最后存入的元素会形成一个树状结构
    2. 构造方法

      • TreeSet() 构造一个新的空set, 该set根据其元素的自然顺序进行排序
      • TreeSet(Comparator <? super E> comparator) 构建一个空的TreeSet, 他根据指定比较器进行排序
    3. 常用方法

      • add(E e) 将指定元素添加到此set
      • first() 返回此set中当前第一元素
      • last() 返回此set中当前最后一个元素
      • floor() 返回此set中小于等于给定元素的最大元素,不存在则返回null
      • higher() 返回此set中严格大于给定元素的最小元素,不存在则返回null
    4. 演示

      public static void main(String[] args) {
       TreeSet<String> set = new TreeSet<>();
       
       set.add("a");
       set.add("d");
       set.add("c");
       set.add("b");
       set.add("e");
       set.add("b");
       set.add("n");
       
       System.out.println(set);//结果: [a, b, c, d, e, n]
      }
      
    5. 添加原理

      • TreeSet会将第一个添加的元素作为中点, 以后添加的元素会先跟中点进行比较, 如果大于就接着跟所比较元素的右边的元素接着比较,如果小于就接着跟所比较元素左边的元素接着比较, 直到无法找到可比较的元素,就会将新添加的这个元素放到当前位置
    6. Comparable接口

      • 所有存入的元素在比较的时候,如果集合没有比较器, 就会将元素本身转成Comparator类型并调用comparTo方法进行比较, 所以我们必须实现Comparato接口,并重写comparTo方法
      • 调用compartTo方法比较
        • 如果方法返回一个小于0的数,表示当前元素小于被比较元素
        • 如果返回 0 表示当前元素等于被比较元素
        • 如果返回一个大于0的数, 表示当前元素大于被比较元素
      • 演示
      public class Student implements Comparable<Student>{
      
       @Override
       public int compareTo(Student o) {
           
           return 0;
       }
      
      }
      
      
    7. Comparator比较器

      • 这是一个接口, 定义了一个compare抽象方法
      • compare方法可以对两个元素进行比较
        • 如果方法返回一个小于0的数,表示参数1小于参数2
        • 如果返回 0 ,表示参数1等于参数2
        • 如果返回一个大于0的数, 表示参数1大于参数2
      • 演示
      public class MyComparator implements  Comparator<Student>{
      
       @Override
       public int compare(Student o1, Student o2) {
           
           return 1;
       }
      }
      
      
    8. 注意事项

      • TreeSet集合的存储原理限定了必须要对存入的元素进行比较
      • 要么存入的元素自身实现Comparable接口, 要么提供外部的实现了Comparator接口的比较器, 否则程序运行就会报错
    9. 测试题

      • 需求: 键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台
      • 演示
      public class MyComparator implements Comparator<Student>{
      
       @Override
       public int compare(Student o1, Student o2) {
           int num = o2.getSum() - o1.getSum();            //根据学生的总成绩降序排列
           return num ;
       }
      }
      
      
      public static void main(String[] args) {
       
       TreeSet<Student> set = new TreeSet<>(new MyComparator());
       
       Student student1 = new Student("小红",100);
       Student student2 = new Student("小明",50);
       Student student3 = new Student("小李",60);
       set.add(student1);
       set.add(student2);
       set.add(student3);
       
       for (Student student : set) {
           System.out.println(student);
       }
      }
      
      

    七. 超级for

    1. 定义

      • Iterator的简写形式
      • 简化数组和Collection集合的遍历
    2. 格式

      for(元素数据类型 变量 : 数组或者Collection集合) {
       使用变量即可,该变量就是当前元素
      }
      
      
    3. 演示

      public static void main(String[] args) {
       
       TreeSet<Student> set = new TreeSet<>(new MyComparator());
       
       Student student1 = new Student("小红");
       Student student2 = new Student("小明");
       Student student3 = new Student("小李");
       set.add(student1);
       set.add(student2);
       set.add(student3);
       
       for (Student student : set) {
           System.out.println(student);
       }
      }
      
      
    4. 三种迭代方式的删除

      • 普通for循环,可以删除,但是需要角标
      • 迭代器,可以删除,但是必须使用迭代器自身的remove方法,否则会出现并发修改异常
      • 超级for循环不能删除

    八. Collections工具类的使用

    1. 定义

      • 一个用于操作Collection集合工具类
    2. 常用方法

      • sort(List<T> list) 根据元素的自然顺序排序
      • swap(List<T> list , int i , int j) 交换集合中两个角标位上的值
      • reverse(List<?> list ) 反转集合中的元素的顺序
      • replaceAll(List<T> list, T oldVal, T newVal) 替换
    3. 演示

      public static void main(String[] args) {
       
       List<String> cl = new ArrayList<>();
       
       cl.add("a");
       cl.add("d");
       cl.add("s");
       cl.add("t");
       cl.add("a");
       cl.add("e");
       
       System.out.println(cl);//[a, d, s, t, a, e]
       
       Collections.sort(cl);
       System.out.println(cl);//[a, a, d, e, s, t]
       
       Collections.swap(cl,1,2);
       System.out.println(cl);//[a, d, a, e, s, t]
       
       Collections.reverse(cl);
       System.out.println(cl);//[t, s, e, a, d, a]
       
       Collections.replaceAll(cl,"a","f");
       System.out.println(cl);//[t, s, e, f, d, f]
      }
      
      

    总结:

    1. ArrayList集合的嵌套
      • 类似于二维数组
    2. Set
      • 去重
      • 无序(集合无序)
    3. HashSet
      • 去重效率高, 尤其是在大数据量下
      • 调用元素的hashCode和equals方法来比较是否相同
    4. LinkedHashSet
      • 即有序(集合有序), 又能去重
      • 效率不高
    5. TreeSet
      • 去重, 元素有序(对存入的元素进行排序)
      • 要求存入的元素必须具备比较的能力或者提供第三方的比较器
      • 元素具备比较的能力 : 元素实现comperable接口, 重写comparTo方法
      • 第三方比较器: 定义类,实现Compartor接口, 从写 compare方法
    6. 超级for
      • 迭代器的简写形式
      • 优点: 格式简单
      • 缺点: 无法进行删除操作
    7. Collections
      • 一个用来操作List集合的工具类

    作业

    1. 第一题

      • 需求: 创建学生类, 定义姓名和年龄属性, 创建多个学生对象, 根据学生的年龄进行排序
      package com.huwenlong.day14;
      //方法一
      import java.util.Comparator;
      import java.util.TreeSet;
      //使用TreeSet和第三方比较器对学生的年龄进行比较
      public class Test01 {
          public static void main(String[] args) {
              TreeSet<Student> treeSet = new TreeSet<>(new Comparator<Student>() {
                  @Override
                  public int compare(Student o1, Student o2) {
                      return o1.getAge()-o2.getAge();
                  }
              });
              treeSet.add(new Student("小红",19));
              treeSet.add(new Student("小明",20));
              treeSet.add(new Student("小王",10));
              treeSet.add(new Student("小赵",7));
              for (Student student : treeSet) {
                  System.out.println(student);
              }
          }
      }
      
      
      package com.huwenlong.day14;
      
      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 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 String toString() {
              final StringBuilder sb = new StringBuilder("Student{");
              sb.append("name='").append(name).append('\'');
              sb.append(", age=").append(age);
              sb.append('}');
              return sb.toString();
          }
      
          @Override
          public int hashCode() {
              return Objects.hash(name, age);
          }
      
          public String getName() {
              return name;
          }
      
          public int getAge() {
              return age;
          }
      }
      
      
      package com.huwenlong.day14;
      
      import java.util.LinkedList;
      //方法二:使用LinkedList并使用冒泡排序
      public class TestDemo06 {
          public static void main(String[] args) {
              LinkedList<Student> linkedList = new LinkedList<>();
              linkedList.add(new Student("小红",19));
              linkedList.add(new Student("小明",20));
              linkedList.add(new Student("小王",10));
              linkedList.add(new Student("小赵",7));
              for (int i = 0; i < linkedList.size()-1; i++) {
                  for (int j = 0; j < linkedList.size()-1-i; j++) {
                      Student s1 = linkedList.get(j);
                      Student s2 = linkedList.get(j+1);
                      if(s1.getAge()>s2.getAge()){
                          Student t = s1;
                          linkedList.set(j,s2);
                          linkedList.set(j+1,t);
                      }
                  }
              }
              for (Student student : linkedList) {
                  System.out.println(student);
              }
          }
      }
      
      
      
    1. 第二题

      • 需求: 从键盘接收一个字符串, 程序对其中所有字符进行排序(重复不重复无所谓啦)
      • 示例: 键盘输入: helloitcast程序打印:acehillostt
      package com.huwenlong.day14;
      //第一种方法:使用StringBuilder,可以处理重复字符
      import java.util.Scanner;
      public class TestDemo07 {
          public static void main(String[] args) {
              Scanner sc = new Scanner(System.in);
              System.out.println("请输入一个字符串:");
              String str = sc.next();
              StringBuilder sb = new StringBuilder(str);
              for (int i = 0; i <sb.length()-1 ; i++) {
                  for (int j = 0; j < sb.length()-1-i; j++) {
                      if(sb.charAt(j)>sb.charAt(j+1)){
                          char ch = sb.charAt(j);
                          sb.setCharAt(j,sb.charAt(j+1));
                          sb.setCharAt(j+1,ch);
                      }
                  }
              }
              System.out.println(sb.toString());
          }
      }
      
      
      
      package com.huwenlong.day14;
      //第二种方式:使用TreeNode,不能处理重复字符
      import java.util.Scanner;
      import java.util.TreeSet;
      
      public class Test02 {
          public static void main(String[] args) {
              Scanner sc = new Scanner(System.in);
              System.out.println("请输入一个字符串:");
              String str = sc.next();
              TreeSet<Character> treeSet = new TreeSet<>();
              for (int i = 0; i < str.length(); i++) {
                  treeSet.add(str.charAt(i));
              }
              for (Character character : treeSet) {
                  System.out.print(character);
              }
          }
      }
      
      
      
      package com.huwenlong.day14;
      
      import java.util.ArrayList;
      import java.util.Collections;
      import java.util.Scanner;
      //使用Collections.sort方法进行排序,可以处理重复字符
      public class Test08 {
          public static void main(String[] args) {
              Scanner sc = new Scanner(System.in);
              String str = sc.next();
              ArrayList<Character> list = new ArrayList<>();
              for (int i = 0; i < str.length(); i++) {
                  list.add(str.charAt(i));
              }
              Collections.sort(list);
              for (Character character : list) {
                  System.out.print(character);
              }
          }
      
      }
      
      
      
    1. 扩展题

      1. 第一题

        • 在一个集合中存储了无序并且重复的字符串,定义一个方法,让其有序(字典顺序),而且还不能去除重复
        • 使用TreeSet进行排序
        package com.huwenlong.day14;
        
        import java.util.ArrayList;
        import java.util.TreeSet;
        
        public class Test03 {
            public static void main(String[] args) {
                ArrayList<String> list = new ArrayList<>();
                list.add("abcdef");
                list.add("poiuy");
                list.add("abcdef");
                list.add("lkjghf");
                list.add("xxzxsd");
                list.add("poiuy");
                ArrayList<String> newList = getSortedString(list);
                for (String s : newList) {
                    System.out.println(s);
                }
            }
            //首先将ArrayList中的内容传入到TreeSet中,去重
            public static ArrayList<String> getSortedString(ArrayList<String> list){
                TreeSet<String> set = new TreeSet<>(list);
                ArrayList<String> newList = new ArrayList<>();
                //然后对于去重后的元素,计算出在原集合中出现的次数,再根据次数存到新字符串中
                for (String s : set) {
                    int count = 0;
                    while(true){
                        int index = list.indexOf(s);
                        if(index == -1)
                            break;
                        count++;
                        list.remove(index);
                    }
                    for (int i = 0; i < count; i++) {
                        newList.add(s);
                    }
                }
                return newList;
            }
        }
        
        
        
    1. 第二题

      • 思考, 能不能将HashSet集合可以存储重复元素(同一个对象)
      package com.huwenlong.day14;
      
      import java.util.HashSet;
      
      public class Test04 {
          public static void main(String[] args) {
              HashSet<Student> set = new HashSet<>();
              Student stu = new Student("小红",20);
              set.add(stu);
              System.out.println(set);
              set.add(stu);
              System.out.println(set);
          }
      }
      
      package com.huwenlong.day14;
      
      import java.util.Objects;
      
      public class Student {
          private String name;
          private int age;
          //自定义一个count属性通过构造方法初始化为0,然后重写hashCode方法,每次调用hashCode都会将count++,根据name age  count三个属性计算哈希值,这样同一对象的前后hash值不一样就可以存储同一个对象了
          private int count;
      
          public Student(String name, int age) {
              this.name = name;
              this.age = age;
              count = 0;
          }
      
          @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 String toString() {
              final StringBuilder sb = new StringBuilder("Student{");
              sb.append("name='").append(name).append('\'');
              sb.append(", age=").append(age);
              sb.append('}');
              return sb.toString();
          }
      
          @Override
          public int hashCode() {
              count++;
              return Objects.hash(name, age ,count);
          }
      
          public String getName() {
              return name;
          }
      
          public int getAge() {
              return age;
          }
      }
      
      
      
      
      

    相关文章

      网友评论

          本文标题:Day14

          本文链接:https://www.haomeiwen.com/subject/tiiugctx.html