83.set集合的概述
-概述:一个不包含重复元素的collection,set集合的方法与collection集合的方法一样,没有特有的方法,主要研究它的子类。
-特点:无索引,不可以重复,无序(存取不一致)
package set;
import java.util.HashSet;
import Collection.Student;
public class demo2 {
public static void main(String[] args) {
HashSet 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 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 hs = new LinkedHashSet<>(); //怎么存怎么取
//HashSet 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 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 list) {
LinkedHashSet 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 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 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{
@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 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 list) {
TreeSet ts = new TreeSet<>(new Comparator() { //匿名内部类
@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 ts = new TreeSet<>(new Comparator() {
@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 ts = new TreeSet<>(new Comparator() { //创建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 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{ //让自定义类实现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个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台