前言:直面自己,敢于正视自己的缺点,并努力完善自己;直面困境,逆境是淘汰竞争者的机会,
别把自己淘汰了;不要觉得自己现在啥也不是,只要努力三年后无论是能力还是回报都会有较大的提升
TreeSet
它是SortedSet接口的实现类,它是一个有序而且唯一的单值类型集合~
TreeSet01:
---------
public class Test01 {
public static void main(String[] args){
TreeSet<String> treeSet = new TreeSet<>();
Collections.addAll(treeSet,"Leon","Andy","Aaron","Jacky","Jay");
System.out.println(treeSet);//打印[Aaron, Andy, Jacky, Jay, Leon]
//因为TreeSet是有序的,所以可以通过first()获取第一个元素,last()获取最后一个元素,pollFirst()获取并删除第一个元素
//pollLast()获取并删除最后一个元素
/*System.out.println(treeSet.first());//打印Aaron
System.out.println(treeSet.last());//打印Leon
System.out.println(treeSet.pollFirst() + ":" + treeSet.size());//打印Aaron:4
System.out.println(treeSet.pollLast() + ":" + treeSet.size());//打印Leon:3*/
//打印treeSet中的前三名
//第一种 打印 Aaron Andy Jacky
int index = 0;
for(String x : treeSet){
System.out.println(x);
if(++index == 3)
break;
}
//第二种
List<String> top3 = new ArrayList<>(3);
while(treeSet.size()!=0 && top3.size() != 3){
top3.add(treeSet.pollFirst());
}
System.out.println(top3);//打印[Aaron, Andy, Jacky]
//遍历
for(String x : treeSet){
System.out.println(x);
}
for(Iterator<String> car = treeSet.iterator();car.hasNext();){
System.out.println(car.next());
}
//常用的创建添加进TreeSet的方法
Set<Integer> set = new TreeSet<>();
set.add(55);
set.add(33);
Collections.addAll(set,44,22,33,66);
System.out.println(set);//打印 [22, 33, 44, 55, 66] 有序 唯一
}
}
----------
1:验证TreeSet有序而且唯一的特点,我们先后向集合当中添加了String对象和Integer对象,
发现重复的元素会直接舍弃,而且它会对元素进行排序
注意:程序中在使用first() last()等方法时,应该声明为TreeSet类型,因为Set接口里面没有first()等方法
*:first():用来得到第一个元素 [元素还在集合中]
last():用来得到最后一个元素 [元素还在集合中]
pollFirst():得到并且移除第一个元素
pollLast():得到并且移除最后一个元素
*:虽然是一个有序集合 但是依然不提供get(int) remove(int)方法,这俩方法是List的专利
TreeSet02:
-----------
public class Test02 {
public static void main(String[] args){
Set<Integer> set1 = new TreeSet<>();
Integer i1 = new Integer(55);
Integer i2 = new Integer(55);
set1.add(i1);
set1.add(i2);
System.out.println(set1.size());//打印1
Set<String> set2 = new TreeSet<>();
String s1 = new String("Tomcmd");
String s2 = new String("Tomcmd");
set2.add(s1);
set2.add(s2);
System.out.println(set2.size());//打印1
}
}
----------
2:TreeSet所谓的唯一不是真正的唯一,我们先后创建两个对象内容相同的Integer和String对象
事实上,他们是内存中不同的对象,但是添加进TreeSet当中时,却被TreeSet视作相同对象从而舍弃一个
TreeSet03:
---------
public class Test03 {
public static void main(String[] args){
Set<Student> set = new TreeSet<>();
Student s1 = new Student("Andy",50);
Student s2 = new Student("Zorro",18);
set.add(s1);//如果不实现Comparable接口,会报异常 Student cannot be cast to java.lang.Comparable
set.add(s2);//实现Comparable接口,让Student类型有了比较的能力,注意 Comparable接口要加泛型
System.out.println(set);//打印 [Zorro:18, Andy:50]
}
}
class Student implements Comparable<Student>{
String name;
int age;
public Student(String name,int age){
this.name = name;
this.age = age;
}
@Override
public String toString(){
return name + ":" + age;
}
@Override
public int compareTo(Student stu){
//this 表示新加进来的对象
//stu 表示老的元素
return this.age -stu.age;
}
}
--------
3:TreeSet要求放入集合当中的元素类型必须要实现Comparable<E>接口,并且实现compreTo(E e)方法,他返回值的意义如下:
返回正数:新元素放在右子树(右边)
返回了零:新元素重复直接舍弃
返回负数:新元素放在左子树(左边)
*:如果我们使用的是TreeSet
那么覆盖equals()和hashCode()方法没有任何意义,因为添加 删除 contains的操作仅仅依赖于compreTo()比较即可
TreeSet04:
真正的场景当中,很可能需要通过多个属性综合得到比较规则,这时候,我们应当学会先尊重什么属性,
就先描述假如什么属性不同,这样可以简化代码、逻辑更加清晰
if(第一个属性不同)
return 第一个属性比较;
if(第二个属性不同)
return 第二个属性比较;
......
--------
public class Test04 {
public static void main(String[] args){
Set<Food> set = new TreeSet<>();
Food f1 = new Food("斩青龙",39,1);
Food f2 = new Food("雪盖火山",38,1);
Food f3 = new Food("霸王鳖鸡",180,2);
Food f4 = new Food("尉迟炒饭",66,3);
Food f5 = new Food("82年的芬达",30,0);
Food f6 = new Food("果子狸炖水鱼",520,2);
Collections.addAll(set,f1,f2,f3,f4,f5,f6);
System.out.println(set);//打印
// [82年的芬达:30 酒水,
// 斩青龙:39 凉菜,
// 雪盖火山:38 凉菜,
// 果子狸炖水鱼:520 热菜,
// 霸王鳖鸡:180 热菜,
// 尉迟炒饭:66 主食]
}
}
class Food implements Comparable<Food>{
String name;
int price;
int type;//[0.酒水 1.凉菜 2.热菜 3.主食 4.汤]
private static String[] data = "酒水,凉菜,热菜,主食,汤".split(",");//共享一份的属性,所以声明成static
public Food(String name,int price,int type){
this.name = name;
this.price = price;
this.type = type;
}
@Override
public String toString(){
return name + ":"+price + " " + data[type];
}
/*
如何排序呢?
优先按照类别升序排列 如果类别相同
则按照价格降序 如果类别和价格都相同
则按照名字排序 如果就连名字都都都相同
也不能舍弃元素~
*/
@Override
public int compareTo(Food f){ //this表示新加入的对象 或者要删除的对象 或者判断是否包含的那一个对象(谁调用compareTo(),谁就是this)
if(this.type != f.type)
return this.type - f.type;
if(this.price != f.price)
return f.price - this.price; //降序排列
if(!this.name.equals(f.name))
return this.name.compareTo(f.name);
return 1;//不能舍弃,也就是还是得添加进来,则不能返回0
}
}
-------
TreeSet05:
TreeSet的add()方法和remove()方法都尊重compareTo()是否返回0
如果compareTo()返回0,那么不同的对象也会视作相同从而舍弃
如果compareTo()不返回0,那么相同的对象也会认定不同
我们应当保证compareTo()是有可能返回0的,不然remove()放将永远无法删除成功
如果万恶的需求导致compareTo()永远不能返回0,那么删除元素必须借助迭代器实现car.remove();
--------
public class Test05 {
public static void main(String[] args){
Set<Teacher> set = new TreeSet<>();
Teacher t1 = new Teacher("Liyang");
set.add(t1);
set.add(t1);
System.out.println(set);//打印 [Liyang, Liyang]
set.remove(t1);
System.out.println(set);//打印 [Liyang, Liyang]
}
}
class Teacher implements Comparable<Teacher>{
String name;
public Teacher(String name){
this.name = name;
}
@Override
public String toString(){
return name;
}
@Override
public int compareTo(Teacher t){
return 1;
}
}
-------
TreeSet06:
千万不要在用迭代器遍历TreeSet的过程当中对TreeSet整体进行添加或者删除操作
否则会触发并发修改异常 ConcurrentModificationException CME
如果一定要去删除,请用迭代器的car.remove()方法
如果一定要去添加,请使用另一个集合暂存数据
-------
public class Test06 {
public static void main(String[] args){
Set<Integer> set = new TreeSet<>();
Collections.addAll(set,55,33,22,44,11);
//删除所有大于30的数
for(Iterator<Integer> car = set.iterator();car.hasNext();){
Integer i = car.next();
if(i > 30)
car.remove();
}
System.out.println(set);//打印 [11,22]
}
}
-------
TreeSet07:
使用TreeSet千万不要在添加元素之后,直接修改参与比较排序的属性
否则有可能会破坏整个树的结构,那么唯一和有序都无法保证
如果需求一定要修改:
a:删除 -> 当心知识点5和知识点6
b:修改属性
c:重新添加回集合 -> 当心知识点6
-------
public class Test07 {
public static void main(String[] args){
TreeSet<Hero> set = new TreeSet<>(new MyComparator());
Hero h1 = new Hero("D大头儿子",30,88);
Hero h2 = new Hero("G隔壁老王",20,60);
Hero h3 = new Hero("H黑猫警长",32,88);
Hero h4 = new Hero("J金刚葫芦娃",20,60);
Hero h5 = new Hero("Z奥特曼",30,6);//谁让你是日本的
Collections.addAll(set,h1,h2,h3,h4,h5);
/*
0xx.请使用比较器制定Hero类的排序规则
该规则要求优先按照武力值降序排列
如果武力值相等 则年龄小的在前
如果武力值和年龄都相同则按照名字随意排
如果都都都一样也不能舍弃元素哦!~
*/
//1st.请问英雄联盟总共有多少个英雄啊?
System.out.println(set.size());
//2nd.请用程序验证有没有叫H黑猫警长的英雄
int x = 0;
for(Iterator<Hero> car = set.iterator();car.hasNext();){
Hero h = car.next();
if("H黑猫警长".equals(h.name)){
System.out.println(" 2nd: 有");
break;
}
x++;
}
if(x == set.size())
System.out.println(" 2nd : 无");
//3rd.大头儿子的年龄收录错了 人家还是个孩纸 不能这么残忍的对待他!他才3岁啊
List<Hero> list = new ArrayList<>();
for(Iterator<Hero> car = set.iterator();car.hasNext();){
Hero h = car.next();
if(h.name.contains("大头儿子")){
car.remove();
h.age = 3;
list.add(h);
}
}
set.addAll(list);
System.out.println(set);
//4th.所有武力值大于80的英雄 收到群体伤害 武力值下降20%
List<Hero> list2 = new ArrayList<>();
for(Iterator<Hero> car = set.iterator();car.hasNext();){
Hero h =car.next();
if(h.power > 80){
car.remove();
h.power = h.power * 4 / 5;
list2.add(h);
}
}
set.addAll(list2);
System.out.println(set);
}
}
class Hero{
String name;
int age;
int power;
public Hero(String name,int age,int power){
this.name = name;
this.age = age;
this.power = power;
}
@Override
public String toString(){
return name + "-" + age + "-" + power;
}
}
class MyComparator implements Comparator<Hero>{
@Override
public int compare(Hero h1,Hero h2){
if(h1.power != h2.power)
return h2.power - h1.power;
if(h1.age != h2.age)
return h1.age - h2.age;
if(!h1.name.equals(h2.name))
return h1.name.compareTo(h2.name);
return 1;
}
}
------
TreeSet08:
底层是红黑树,一种自平衡的二叉树...
在添加元素之后可能会发生旋转修复操作
所以,开始是根的元素,未必永远是根
------
public class Test08 {
public static void main(String[] args){
Set<A> set = new TreeSet<>();
A a1 = new A(1);
A a2 = new A(2);
A a3 = new A(3);
A a4 = new A(4);
set.add(a1);
System.out.println("=======");
set.add(a2);
System.out.println("=======");
set.add(a3);
System.out.println("=======");
set.add(a4);
System.out.println("=======");
/*打印结果
新元素A1 VS 老元素A1
=======
新元素A2 VS 老元素A1
=======
新元素A3 VS 老元素A1
新元素A3 VS 老元素A2
=======
新元素A4 VS 老元素A2
新元素A4 VS 老元素A3
=======
*/
}
}
class A implements Comparable<A>{
int num;
public A(int num){
this.num = num;
}
@Override
public String toString(){
return String.valueOf(num);
}
@Override
public int compareTo(A a){
System.out.println("新元素A"+this.num + " VS " + "老元素A" + a.num);
return this.num - a.num;
}
}
------
TreeSet09:
TreeSet构造方法的参数:比较器
比较器可以帮助我们在不修改一个类的任何代码的情况下还能指定这个类的比较规则
Comparator compare(1,2)
使用比较器结合TreeSet的时候,必须直接构造方法传入!而List当中构造方法是不提供比较器的参数的
此时要想改变比较规则,只能使用Collections.sort(List,Comparator);
*:Comparable和Comparator的区别
首先他们存在的包就不同
java.lang.Comparable -> lang包 语言基础包
java.util.Comparator -> util包 工具包
抽象方法不同
Comparable: compareTo(1)
Comparator: compare(1,2)
他们的语义语境完全不同
Comparable是一个形容词 如果某个类直接实现这个接口
代表这个类型的对象是有能力比较排序的,可以直接放入TreeSet或者TreeMap集合
class Student implements Comparable<Student>{
...此时表示学生类自身能够完成比较排序
可以直接放入TreeSet或者TreeMap
}
Comparator 是一个名词 如果某个类直接实现这个接口
代表这个类型的对象是用来比较另一个类型的工具而已!!!
class Student implements Comparator<Teacher>{
...此时表示学生类的对象是用来比较老师的工具
学生类的对象应当在创建TreeSet的时候通过构造方法传入
}
*关于比较器结合List
将List集合从添加顺序改变成我们所需要的顺序
*:Collections.sort(List);
*:Collections.reverse(List);
*:Collections.sort(List,Comparator);
#:别忘记Collections.addAll(List,Object...);
#:注意 Set集合不能作为Collections.sort()的参数,源码中只写了list作为参数的sort()方法
-------
public class Test09 {
public static void main(String[] args){
List<Integer> list = new ArrayList<>();
Collections.addAll(list,55,33,24,57,78,66);
System.out.println(list);//打印 [55, 33, 24, 57, 78, 66]
//现在要将其排序 Collections.sort(list)
Collections.sort(list);
System.out.println(list);//打印[24, 33, 55, 57, 66, 78] 这里只能是升序排列,因为Integer类实现了Comparable接口,比较规则已经写好
//降序排序
/*Collections.reverse(list);
System.out.println(list);//打印 [78, 66, 57, 55, 33, 24]*/
Collections.sort(list,new MyComparator());
System.out.println(list);//[24, 33, 55, 57, 66, 78]
}
}
class MyComparator implements Comparator<Integer>{
@Override
public int compare(Integer i1,Integer i2){
return i1 - i2;
}
}
-------
JCF之单值类型集合内容汇总图