83.set集合的概述
-概述:一个不包含重复元素的collection,set集合的方法与collection集合的方法一样,没有特有的方法,主要研究它的子类。
-特点:无索引,不可以重复,无序(存取不一致)
package set; import java.util.HashSet; import Collection.Student; public class demo2 { public static void main(String[] args) { HashSet<Student> hs = new HashSet<>(); //当对自定义对象使用hashset时,需要重写自定义类的hascode和equals方法 hs.add(new Student("张三",23)); hs.add(new Student("张三",23)); hs.add(new Student("李四",24)); hs.add(new Student("王五",25)); for (Student s : hs) { System.out.println(s.getName()+".."+s.getAge()); } } } //Studnet自定义类 @Override public int hashCode() { final int prime = 31; int result = 1; result = prime * result + age; result = prime * result + ((name == null) ? 0 : name.hashCode()); return result; } @Override public boolean equals(Object obj) { if (this == obj) //调用的对象和传入的对象是一个对象 return true; if (obj == null) //传入的对象不存在 return false; if (getClass() != obj.getClass()) //判断两个对象的字节码文件是否是同一个字节码 return false; Student other = (Student) obj; //向下转型 if (age != other.age) return false; if (name == null) { if (other.name != null) return false; } else if (!name.equals(other.name)) return false; return true; }-Hashset原理:
*我们使用set集合都是需要去掉重复元素的,如果在存储时候逐个equals()比较,效率较低,哈希算法提高了去重复的效率,降低了使用equals方法的次数
*当Hashset调用add方法存储对象的时候,先调用对象的hashCode方法获得一个哈希值,然后再集合中查找是否有哈希值相同的对象
-*如果没有哈希值相同的对象就直接存入集合。
-*如果有哈希值相同的对象,就和哈希值相同的对象逐个进行equals比较,比较结果为false就存入,为true就不存入
-将自定义类的对象存入HashSet去重复
*类中必须重写hashCode方法和equals方法
*hashCode():属性相同的对象返回值必须相同,属性不同的返回值尽量不同(提高效率)
*equals():属性相同返回true,属性不相同返回false,返回false的时候存储入集合
-LinkedHashSet的概述和特点:
-概述:链表形式的HashSet
-特点:
*底层由链表实现,是Set集合中唯一一个能保证怎么存就怎么取的集合对象
*因为是HashSet的子类,所以可以保证元素的唯一性
-范例1:编写一个程序,获得10个1-20的随机数,要求随机数不能重复,并打印到控制台上
package set; import java.util.HashSet; import java.util.Random; public class demo3 { public static void main(String[] args) { //1.用Random类创建对象 Random r = new Random(); //2.用HashSet存储10个不能重复的随机数集合 HashSet<Integer> hs = new HashSet<>(); //3.利用循环添加元素 while(hs.size() < 10){ //添加1-20的随机数 hs.add(r.nextInt(20)+1); } //4.foreach循环遍历 for (Integer integer : hs) { System.out.println(integer); } } } //编写一个程序,获得10个1-20的随机数,要求随机数不能重复,并打印到控制台上
-范例2:利用Scanner从键盘读取一行输入,去掉其中重复元素,打印出不同的那些字符
package set; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedHashSet; import java.util.Scanner; public class demo4 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); //创建Scanner对象 while(sc.hasNext()){ String s = new String(sc.nextLine()); //将键盘输入赋值给s char[] arr = s.toCharArray(); LinkedHashSet<Character> hs = new LinkedHashSet<>(); //怎么存怎么取 //HashSet<Character> hs = new HashSet<>(); //无序输出 for (char c : arr) { hs.add(c); } /*for (int i = 0; i < arr.length; i++) { hs.add(arr[i]); }*/ for (Character c : hs) { System.out.print(c); } } /*大撒旦去我的和dsadas1232131 a的d旦大和我1撒2s3去*/ } } /*利用Scanner从键盘读取一行输入,去掉其中重复元素,打印出不同的那些字符*/-范例3:去除集合中重复的元素
package set; import java.util.ArrayList; import java.util.LinkedHashSet; import java.util.List; public class demo5 { /* * 分析: * 1.创建集合 * 2.单独定义方法去重 * 3.打印集合 * */ public static void main(String[] args) { List<String> list = new ArrayList<>(); list.add("a"); list.add("a"); list.add("b"); list.add("b"); list.add("c"); list.add("d"); list.add("f"); list.add("c"); getSingle(list); System.out.println(list); } /* * 分析: * 1.创建LinkedHashSet集合 * 2.将list集合中所有的元素添加到linkedHashSet集合中 * 3.删除原有的list集合 * 4.将linkedHashSet中的元素添加到空的list集合中 * */ public static void getSingle(List<String> list) { LinkedHashSet<String> lhs = new LinkedHashSet<>(); lhs.addAll(list); //将list集合中所有的元素添加到linkedHashSet集合中 /*for (String s : list) { lhs.add(s); }*/ /*list.removeAll(list); */ list.clear(); //删除集合中的所有元素 /*for (String s : lhs) { list.add(s); }*/ list.addAll(lhs); //将linkedHashSet中的元素添加到空的list集合中 } } //去除集合中的重复元素84.TreeSet集合的概述和使用
-概述:TreeSet集合是用来对集合进行排序的,也可以保证元素的唯一性
-特点:TreeSet底层是通过二叉树来实现的,小的存储在左边(负数),相等的不保存(0),大的存储在右边(正数)
*compareTo方法:在TreeSet集合如何存储元素取决于compareTo方法的返回值
*TreeSet是用来排序的,可以指定一个顺序,对象存入之后要按照指定的顺序排序
-使用方式:
*自然顺序(comparable):
*TreeSet类中的add方法会将存入的对象自动提升为comparable类型
*调用对象的comparable方法和集合中的对象比较
*根据compareTo方法返回的结果进行存储
*比较器顺序(comparator):
*创建TreeSet集合的时候可以制定一个比较器(comparator)
*如果传入了comparator的子类对象,那么TreeSet就会按照比较器中的顺序进行排序
*add()方法内部会自动调用comparator接口中的compare()方法进行排序
*两种方式的区别:
*TreeSet构造函数如果什么都不传,默认按照类中comparable的顺序(没有就报错ClasscastException)
*TreeSet如果传入comparator,就优先按照comparator
-TresSet存储自定义对象
*需要让自定义类实现Camparable接口中的compareTo方法
*compareTo返回0的时候集合只有一个元素
返回正数的时候怎么存怎么取
返回负数的时候倒序存储
package treeset; import java.util.TreeSet; import Collection.Student; public class demo2 { public static void main(String[] args) { TreeSet<Student> ts = new TreeSet<>(); ts.add(new Student("张三",23)); ts.add(new Student("李四",24)); ts.add(new Student("王五",43)); ts.add(new Student("赵六",33)); ts.add(new Student("周七",23)); ts.add(new Student("张三",23)); System.out.println(ts); for (Student s : ts) { System.out.println(s.getName()+".."+s.getAge()); } } } student类 @Override//重写comparable接口中的方法 /* * 返回正数是怎么存怎么取 * 返回负数是倒序存储 * 返回0集合只有一个元素 * */ public int compareTo(Student o) { int num = this.age - o.age; return num == 0 ? this.name.compareTo(o.name) : num; }-指定比较器进行排序
package treeset; import java.util.Comparator; import java.util.TreeSet; public class demo2 { public static void main(String[] args) { TreeSet<String> ts = new TreeSet<>(new comparetest()); //comparator c = new comparetest(); 指定比较器 ts.add("aaaaa"); ts.add("w"); ts.add("z"); ts.add("nba"); ts.add("cba"); System.out.println(ts); } } class comparetest implements Comparator<String>{ @Override public int compare(String o1, String o2) { int num = o1.length() - o2.length(); //字符串长度为主要条件 return num == 0 ? o1.compareTo(o2) : num; //字符串内容是否相等为次要条件 } }
-范例:在一个集合中存储了无序且重复的字符串,定义一个方法,让其有序(字典顺序),而且不能去重
package treeset; import java.util.ArrayList; import java.util.Comparator; import java.util.TreeSet; public class demo3 { public static void main(String[] args) { ArrayList<String> list = new ArrayList<>(); list.add("ccc"); list.add("ccc"); list.add("ccc"); list.add("aaa"); list.add("aaa"); list.add("ccc"); list.add("bbb"); list.add("bbb"); sort(list); System.out.println(list); } /* * 分析: * 创建TreeSet集合对象,因为String本身就具备比较功能,但是重复不会保留,所以我们用比较器 * 将List集合中的所有元素添加到TreeSet集合中,对其排序,重复保留 * 清空List集合 * 将TreeSet集合中排好序的元素添加到List集合中 * */ public static void sort(ArrayList<String> list) { TreeSet<String> ts = new TreeSet<>(new Comparator<String>() { //匿名内部类 @Override //重写comparator接口的方法 public int compare(String o1, String o2) { int num = o1.compareTo(o2); return num == 0 ? 1 : num ; //当两个字符串相同时,使其保留 } }); ts.addAll(list); //将list集合中的元素复制到TreeSet集合中 list.clear(); list.addAll(ts); } } /* *在一个集合中存储了无序且重复的字符串,定义一个方法,让其有序(字典顺序),而且不能去重 * */-范例:从键盘接口一个字符串,程序对其中所有字符串进行排序,例如输入:helloitcast 输出 acehillostt
package treeset; import java.util.Comparator; import java.util.Scanner; import java.util.TreeSet; /* * 分析: * 先将字符串转换为字符数组 * 创建一个character类型的TreeSet集合,并定义比较器,使其重复元素保留 * 将arr中的元素添加到TreeSet集合中 * 打印TreeSet集合 * */ public class demo4 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); while(sc.hasNext()){ String s = new String(sc.nextLine()); char[] arr = s.toCharArray(); TreeSet<Character> ts = new TreeSet<>(new Comparator<Character>() { @Override public int compare(Character o1, Character o2) { //若o1等于o2,则保留 int num = o1.compareTo(o2); return num == 0 ? 1 : num; } }); for (Character c : arr) { //遍历arr,将arr数组中的元素添加到ts集合中 ts.add(c); } for (Character c : ts) { System.out.print(c); } } } } //从键盘接口一个字符串,程序对其中所有字符串进行排序,例如输入:helloitcast 输出 acehillostt-范例:程序启动后,从键盘输入接收多个整数,直到输入quit结束输入,把所有输入的整数倒序排列打印
package treeset; import java.util.Comparator; import java.util.Scanner; import java.util.TreeSet; /* * 分析: * 1.创建scanner对象,键盘录入 * 2.创建TreeSet集合对象,TreeSet集合中传入比较器 * 3.无限循环不断接收整数,遇到quit退出循环,因为quit时字符串,所以键盘录入的形式都应该是字符串 * 4.判断是否是quit,是就退出,不是就将其转换为integer类型,并将其添加到TreeSet集合中 * 5.打印TreeSet集合 * */ public class demo5 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); TreeSet<Integer> ts = new TreeSet<>(new Comparator<Integer>() { //创建TreeSet集合 @Override public int compare(Integer o1, Integer o2) { //设置比较器,使其倒叙输出,且重复元素保留 int num = o2 - o1; //自动拆箱 return num == 0 ? 1 : num; } }); while(true){ //设置无限循环,不断接收整数 String line = sc.nextLine(); if("quit".equals(line)){ //当输入quit时退出循环 break; }else{ Integer i = new Integer(line); //将String转换为integer ts.add(i); //将integer对象添加到集合中 } } for (Integer i : ts) { System.out.println(i); } } } //程序启动后,从键盘输入接收多个整数,直到输入quit结束输入,把所有输入的整数倒序排列打印-范例:键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台
package treeset; import java.util.Scanner; import java.util.TreeSet; /* * 分析: * 1.定义一个学生类: * 成员变量:姓名,语文成绩,数学成绩,英语成绩 * 成员方法:空参,有参构造的参数为姓名,语文成绩,数学成绩,英语成绩 * toString方法,在遍历集合中的Student对象打印对象引用的时候显示属性值 *2.键盘录入创建Scanner对象 *3.创建TreeSet集合对象,在TreeSet的构造函数传入比较器,按照总分比较 *4.录入5个学生,以集合中的学生个数为判断条件,如果size小于5就进行存储 *5.将录入的字符串进行切割,用逗号来进行切割,返回一个字符数组,将数组从第二位元素开始到末尾的元素转换为int类型 *6.将转换后的结果封装为student对象,并添加到TreeSet集合中 *7.打印TreeSet集合 * */ public class demo6 { public static void main(String[] args) { Scanner sc = new Scanner(System.in); //创建键盘录入对象 TreeSet<Student> ts = new TreeSet<>(); //创建TreeSet集合 System.out.println("请输入成绩,格式为:姓名,语文成绩,数学成绩,英语成绩"); while(ts.size()<5){ String line = sc.nextLine(); String[] arr = line.split(","); //将字符串切割为字符数组 int CS = Integer.parseInt(arr[1]); int MS = Integer.parseInt(arr[2]); int ES = Integer.parseInt(arr[3]); ts.add(new Student(arr[0],CS,MS,ES)); //将转换后的结果封装为student对象 } for (Student student : ts) { System.out.println(student); } } } class Student implements Comparable<Student>{ //让自定义类实现comparable接口,也可以实现比较 private String name; private int CS; //语文成绩 private int MS; //数学成绩 private int ES; //英语成绩 private int sum; public int getSum() { return sum; } public Student(String name, int cS, int mS, int eS) { super(); this.name = name; CS = cS; MS = mS; ES = eS; this.sum = this.CS + this.MS + this.ES ; } public Student() { super(); } @Override public int compareTo(Student o) { int num = (o.CS+o.MS+o.ES) - (this.CS+this.MS+this.ES); return num == 0 ? 1 : num; } @Override //重写toString方法 public String toString() { return name+","+CS+","+MS+","+ES+","+sum; } } //键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台
