17.01_HashSet存储字符串并遍历
- A:Set集合概述及特点
public class HashSet<E>extends AbstractSet<E>implements Set<E>, Cloneable, Serializable
// Set集合,无索引,无重复数据,无序(存储不一致)
HashSet<String> set = new HashSet<>();
set.add("a");
set.add("a"); //因为set集合不能存储重复数据,所以这里存储失败,返回false
set.add("xxoo");
for (String string : set) { //迭代,增强for
System.out.println(string);
}
17.02_HashSet存储自定义对象保证元素唯一性
-
核心:重写自定义对象的
hashCode()
和equals()
方法 - 自动生成即可。Eclipse自动生成hashCode和equals方法
@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;
}
为什么Eclipe自动生成hashCode会选择31
1.31是一个质数,质数能被1和自身整除,减少重复性
2.31这个数不大也不小
3.31这个数好算,2的五次方-1,2向左移动5次减1
17.04_HashSet如何保证元素唯一性的原理
- 1.HashSet原理
- 我们使用Set集合都是需要去掉重复元素的, 如果在存储的时候逐个
equals()
比较, 效率较低,哈希算法提高了去重复的效率, 降低了使用equals()
方法的次数 - 当
HashSet
调用add()
方法存储对象的时候, 先调用对象的hashCode()
方法得到一个哈希值, 然后在集合中查找是否有哈希值相同的对象- 如果没有哈希值相同的对象就直接存入集合
- 如果有哈希值相同的对象, 就和哈希值相同的对象逐个进行
equals()
比较,比较结果为false
就存入,true
则不存
- 我们使用Set集合都是需要去掉重复元素的, 如果在存储的时候逐个
- 2.将自定义类的对象存入
HashSet
去重复- 类中必须重写
hashCode()
和equals()
方法 -
hashCode()
: 属性相同的对象返回值必须相同, 属性不同的返回值尽量不同(提高效率) -
equals()
: 属性相同返回true, 属性不同返回false,返回false的时候存储
- 类中必须重写
17.05_LinkedHashSet的概述和使用
//LinkedHashSet 底层是链表实现的,是Set集合中唯一一个能保证怎么存就怎么取的集合对象
//虽然存顺序和取顺序是一样的, 但是并没有索引
//因为HashSet的子类,所以也能保证元素是唯一的
LinkedHashSet<String> link = new LinkedHashSet<>();
link.add("a");
link.add("a");
link.add("b");
System.out.println(link); // [a,b]
17.06_产生10个1-20之间的随机数要求随机数不能重复
需求:编写一个程序,获取10个1至20的随机数,要求随机数不能重复。并把最终的随机数输出到控制台。
HashSet<Integer> set = new HashSet<>();
Random random = new Random();
while (10 > set.size()) {
set.add(random.nextInt(20) + 1); //注意这里的随机数方法, +1是因为随机数方法是前闭后开的
}
System.out.println(set); //这里也可以使用foreach循环输出
17.07_集合框架(练习)
- 使用Scanner从键盘读取一行输入,去掉其中重复字符, 打印出不同的那些字符
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
sc.close();
char[] arr = str.toCharArray(); //将字符串转换成字符数组
LinkedHashSet<Character> set = new LinkedHashSet<>(); //创建LinkedHashSet集合对象(为了跟输入顺序一致)
for (char c : arr) {
set.add(c);
}
System.out.println(set); //输入xxoo123,输出[x,o,1,2,3]
17.08_集合框架(练习)
// 将集合中的重复元素去掉
public static void getSingle(List<String> list) {
LinkedHashSet<String> lhs = new LinkedHashSet<>();
lhs.addAll(list); //将list集合中的所有元素添加到lhs
list.clear(); //清空原集合
list.addAll(lhs); //将去除重复的元素添回到list中
}
17.09_TreeSet存储Integer类型的元素并遍历
// 1.TreeSet能保证数据唯一,2.TreeSet是用来对元素排序的
TreeSet<Integer> ts = new TreeSet<>();
ts.add(3);
ts.add(2);
ts.add(2);
ts.add(1);
System.out.println(ts); //输出 [1, 2, 3]
17.10_TreeSet存储自定义对象
TreeSet<Person> ts = new TreeSet<>();
ts.add(new Person("我日", 20));
ts.add(new Person("我2", 22));
ts.add(new Person("我xo", 80));
System.out.println(ts);
// 1. 直接存储,会运行报错
// 2. 想要不报错,Person类必须实现Comparable<T>接口
// 3.Comparable<T>接口的规律如下:
@Override
public int compareTo(Person o) {
//当compareTo方法返回0 ,集合只有一个元素
//当compareTo方法返回正数,集合怎么存,就怎么取
//当compareTo方法返回负数,集合就会倒序
int num = this.age - o.age ; //年龄为主要条件,年龄一样比较姓名
return num == 0 ? this.name.compareTo(o.name) : num;
}
17.11_TreeSet保证元素唯一和自然排序的原理和图解
TreeSet.png17.12_TreeSet存储自定义对象并遍历练习1
TreeSet存储自定义对象并遍历练习1(按照姓名排序)
关键-->Person的compareTo方法
public int compareTo(Person o) {
int num = this.name.compareTo(o.name); //姓名是主要条件
return num == 0 ? this.age - o.age : num; //年龄是次要条件
}
// 字符串的比较,是比较字符串每个字符的Unicode值
17.14_TreeSet保证元素唯一和比较器排序的原理及代码实现
//匿名类 实现构造器
Comparator<String> com = new Comparator<String>() {
@Override
public int compare(String o1, String o2) {
// 安装字符串长度比较
int num = o1.length() - o2.length();
return num == 0 ? o1.compareTo(o2) : num; //长度相同比较内容
}
};
// 比较器排序 TreeSet有个传入构造器的构造方法
TreeSet<String> ts = new TreeSet<>(com);
ts.add("aabbcc");
ts.add("0125");
ts.add("c");
System.out.println(ts);
17.15_TreeSet原理
- TreeSet是用来排序的, 可以指定一个顺序, 对象存入之后会按照指定的顺序排列
- a.自然顺序(Comparable)
- TreeSet类的add()方法中会把存入的对象提升为Comparable类型
- 调用对象的compareTo()方法和集合中的对象比较
- 根据compareTo()方法返回的结果进行存储
- b.比较器顺序(Comparator)
- 创建TreeSet的时候可以制定 一个Comparator
- 如果传入了Comparator的子类对象, 那么TreeSet就会按照比较器中的顺序排序
- add()方法内部会自动调用Comparator接口中compare()方法排序
- 调用的对象是compare方法的第一个参数,集合中的对象是compare方法的第二个参数
- c.两种方式的区别
- TreeSet构造函数什么都不传, 默认按照类中Comparable的顺序(没有就报错ClassCastException)
- TreeSet如果传入Comparator, 就优先按照Comparator
17.16_集合框架(练习一)
- 在一个集合中存储了无序并且重复的字符串,定义一个方法,让其有序(字典顺序),而且还不能去除重复
ArrayList<String> list = new ArrayList<>();
list.add("ccc");
list.add("ccc");
list.add("aaa");
list.add("aaa");
list.add("bbb");
list.add("ddd");
list.add("ddd");
Comparator<String> com = new Comparator<String>() { //匿名构造器
@Override
public int compare(String s1, String s2) {
int num = s1.compareTo(s2);
return num == 0 ? 1 : num; //如果内容一样返回一个不为0的数字即可
}
};
TreeSet<String> set = new TreeSet<>(com);
set.addAll(list); //讲ArrayList的元素,一次性添加到TreeSet里面
list.clear(); //清空原来的ArrayList
list.addAll(set); //再将排序后的添加来
System.out.println(list);
17.17_集合框架(练习二)
- 从键盘接收一个字符串, 程序对其中所有字符进行排序,例如键盘输入: helloitcast程序打印:acehillostt
Scanner sc = new Scanner(System.in);
String str = sc.nextLine();
sc.close();
char[] arr = str.toCharArray(); //转为char[]数组
// 方法一
Arrays.sort(arr); // Arrays排序
System.out.println(arr); // 搞定
// 方法二 (使用TreeSet)
Comparator<Character> com = new Comparator<Character>() {
@Override
public int compare(Character c1, Character c2) {
int temp = c1 - c2; //自动拆箱
return temp == 0 ? 1 : temp;
}
};
TreeSet<Character> set = new TreeSet<>(com);
for (Character ch : arr) { //其实这里Character和char都可以,自动装箱
set.add(ch);
}
str = "";
for (Character character : set) { //转字符串
str += character;
}
System.out.println(str);
17.18_集合框架(练习三)
- 程序启动后, 可以从键盘输入接收多个整数, 直到输入quit时结束输入. 把所有输入的整数倒序排列打印.
Scanner sc = new Scanner(System.in);
TreeSet<Integer> set = new TreeSet<>(new Comparator<Integer>() { //匿名类
@Override
public int compare(Integer t1, Integer t2) {
int num = t2 - t1 ; //自动拆箱 使用t2.compareTo(t1)也可以
return num == 0 ? 1 : num;
}
});
while (true) {
String str = sc.nextLine();
//如果字符串常量和变量比较,常量放前面,这样不会出现空指针异常,变量里面可能存储null
if ("quit".equals(str)) break;
set.add(Integer.valueOf(str)); //两个方法都可以:Integer.parseInt(str);
// 其实这里应该加异常处理,后面会异常再讲
}
sc.close();
System.out.println(set);
17.19_键盘录入学生信息按照总分排序后输出在控制台
- 需求:键盘录入5个学生信息(姓名,语文成绩,数学成绩,英语成绩),按照总分从高到低输出到控制台。
Scanner sc = new Scanner(System.in);
System.out.println("请输入5个学生成绩格式是:(姓名,语文成绩,数学成绩,英语成绩)");
TreeSet<Student> ts = new TreeSet<>(new Comparator<Student>() {
@Override
public int compare(Student s1, Student s2) {
int num = s2.getSum() - s1.getSum(); //根据学生的总成绩降序排列
return num == 0 ? 1 : num;
}
});
while(ts.size() < 5) {
String line = sc.nextLine();
try {
String[] arr = line.split(","); //分割字符串,方法需要记住!
int chinese = Integer.parseInt(arr[1]); //转换语文成绩
int math = Integer.parseInt(arr[2]); //转换数学成绩
int english = Integer.parseInt(arr[3]); //转换英语成绩
ts.add(new Student(arr[0], chinese, math, english));
} catch (Exception e) {
System.out.println("录入格式有误,输入5个学生成绩格式是:(姓名,语文成绩,数学成绩,英语成绩");
}
}
sc.close();
System.out.println(ts);
17.20_day17总结
- 1.List 集合遍历方法:
- a.普通for循环, 使用
get()
逐个获取元素 - b.调用
iterator()
方法得到Iterator
, 使用hasNext()
和next()
方法 - c.增强for循环, 只要可以使用
Iterator
的类都可以用 - d.
Vector
集合可以使用Enumeration
的hasMoreElements()
和nextElement()
方法
- a.普通for循环, 使用
- 2.Set集合遍历方法
- a.调用
iterator()
方法得到Iterator
, 使用hasNext()
和next()
方法 - b.增强for循环, 只要可以使用
Iterator
的类都可以用
- a.调用
- 3.普通for循环,迭代器,增强for循环是否可以在遍历的过程中删除
- 普通for循环 --> 能 --> i(索引)需要--
- 迭代器 --> 能,但是需要使用迭代器的删除方法
- 增强for循环 --> 不能
END。
我是小侯爷。
在魔都艰苦奋斗,白天是上班族,晚上是知识服务工作者。
如果读完觉得有收获的话,记得关注和点赞哦。
非要打赏的话,我也是不会拒绝的。
网友评论