黑马程序员 java基础之TreeSet集合
/* set:无序,元素不重复 <-HashSet:数据结构是哈希表,线程是非同步的 保证元素唯一性的原理:判断元素的hashCode值是否相同 如果相同,还会继续判断元素的equals方法,是否为true. <-TreeSet:可以对set集合中的元素进行排序,线程是非同步的. 底层数据结构是二叉树(更确切说是红黑树:红黑树的算法特别复杂,以后有时间单独写一篇进行讨论) 保证数据元素唯一性的依据: compareTo方法. remove,contains在查找元素过程中需要使用compareTo方法判断. TreeSet排序的第一种方式: 让元素自身具备比较性,元素需要实现Comparable接口,复写compareTo方法 这种方式叫元素的自然顺序/默认顺序 (排序示意图) */ package treeset; import java.util.*; class TreeSetDemo{ public static void main(String[] args){ /* TreeSet ts=new TreeSet(); ts.add("cdef"); ts.add("aaa"); ts.add("bca"); ts.add("Dbcd"); for(Iterator it=ts.iterator();it.hasNext();) System.out.println(it.next()); */ /* String类中实现了Comparable接口,复写了接口中的toCompare方法 使字符串按照字符的ASCII码从小到大排序. */ stuMethod(); } static void stuMethod(){ TreeSet ts=new TreeSet(); ts.add(new Student("zhang",15)); ts.add(new Student("wang",12)); ts.add(new Student("liu",20)); ts.add(new Student("zong",12));//仅年龄相同 ts.add(new Student("liu",20));//姓名年龄均相同 for(Iterator it=ts.iterator();it.hasNext();){ Student stu=(Student)it.next(); System.out.println(stu.getName()+" "+stu.getAge()); } } } //自定义类,向TreeSet集合中存储自定义对象学生, //希望按照学生的年龄进行排序,当年龄和姓名均相同时,视为同一个人(对象) //该接口强制让学生具备比较性 //排序时,当主要条件相同时,一定要判断下次要条件 class Student implements Comparable{ private String name; private int age; Student(String name,int age){ this.name=name; this.age=age; } public String getName(){ return name; } public int getAge(){ return age; } //复写compareTo public int compareTo(Object obj){ if(!(obj instanceof Student)) throw new RuntimeException("不是Student对象"); Student stu= (Student)obj; //为了查看怎么排序的 System.out.println(this.name+" "+this.age+ "...compareTo..."+stu.name+" "+stu.age); if(this.age>stu.age) return 1; else if(this.age==stu.age)//可以在判断条件加上&&this.name==stu.name //更好的方法,当年龄相同时,对姓名进行排序 return this.name.compareTo(stu.name); //return 0; /* 负整数、零或正整数,根据此对象是小于、等于还是大于指定对象。 return 0 ,TreeSet认为相同对象,不再存入集合(但第一次,自身与自身比较 个人认为为了判断是否具有可比性, 即使返回0,底层通过某种判断->该集合中没有该元素->加入集合) ) */ return -1; } } /* (API) 当使用TreeSet()构造函数时: 构造一个新的空 set, 该 set 根据其元素的自然顺序进行排序。(字典顺序,数字大小顺序等等) 插入该 set 的所有元素都必须实现 Comparable 接口。 另外,所有这些元素都必须是可互相比较的:对于 set 中的任意两个元素 e1 和 e2, 执行 e1.compareTo(e2) 都不得抛出 ClassCastException。 如果用户试图将违反此约束的元素添加到 set (例如,用户试图将字符串元素添加到其元素为整数的 set 中), 则 add 调用将抛出 ClassCastException。 */
第二种排序方式
/* TreeSet: 第一种排序方式: 让元素自身具备比较性,元素需要实现Comparable接口,复写compareTo方法 这种方式叫元素的自然顺序/默认顺序 第二种排序方式: 当元素自身不具备比较性时,或者具备的比较性不是所需要的. (例如我不想按年龄排,按姓名排序,当实现的Comparable 此时代码已封装不能改动) 这时就需要让集合自身具备比较性. 在集合初始化时,就有了比较方式. 当两种方式都存在时,以比较器为主.(根据需要采用不同的比较方式) 定义一个类,实现Comparator接口,覆写compare方法. */ package treeset; import java.util.TreeSet; import java.util.Comparator; import java.util.Iterator; class MyCompare implements Comparator{ public int compare(Object obj_1,Object obj_2){ //利用String类的compareTo方法,此时代码不健壮 //可能出现姓名相同而年龄不同的人->视为不同人 //因此同样判断次要条件->年龄 Student stu_1=(Student)obj_1; Student stu_2=(Student)obj_2; int result=stu_1.getName().compareTo(stu_2.getName()); if(result==0){ return stu_1.getAge()-stu_2.getAge(); //或利用Integer封装整数 //return new Integer(stu_1.getAge()).compareTo(stu_2.getAge()); } return result; } } class TreeSetDemo2{ public static void main(String[] args){ TreeSet ts=new TreeSet(new MyCompare());//该位置传入指定比较器 ts.add(new Student("zhang",15)); ts.add(new Student("wang",12)); ts.add(new Student("liu",20)); ts.add(new Student("zong",14)); ts.add(new Student("zong",12)); for(Iterator it=ts.iterator();it.hasNext();){ Student stu=(Student)it.next(); System.out.println(stu.getName()+" "+stu.getAge()); } } }
TreeSet两种排序方式对比:
/* 两种排序方式对比: ①实现Comparable,复写compareTo: 排序算法和Student类绑定(封装在Student类中), Student只有一种排序算法并且只能有一种,这是因为 我只能复写一次compareTo.这时,这种方法局限性体现出来了. ②自定义类实现Comparator,复写compare: 之所以提供比较器排序接口, 是因为有时需要对同一对象进行多种不同方式的排序, 这点自然排序Comparable不能实现。 另外,Comparator 接口的一个好处是将比较排序算法和实体类分离了(而不再其内部),更加灵活。 、TreeSet():根据TreeSet中元素实现的 Comparable 接口的 compareTo 方法比较排序 、TreeSet(Comparator comparator):根据给定的 comparator 比较器,对 TreeSet 中的元素比较排序 */
Comparator简单练习:
/* 按照字符串长度排序 return s1.length()-s2.length(); 字符串本身具备比较性,它的比较方式不是所需要的. 这时只能采用实现Comparator */ package treeset; import java.util.*; class StringLenCom implements Comparator{ public int compare(Object obj_1,Object obj_2){ String str_1=(String)obj_1; String str_2=(String)obj_2; int num=str_1.length()-str_2.length(); System.out.println(str_1+"...compare..."+str_2+" "+num); if(num==0){//两个字符串相同,不处理,认为相同对象,不再存入集合 return str_1.compareTo(str_2); } return num; } } class TreeSetTest{ public static void main(String[] args){ TreeSet ts=new TreeSet(new StringLenCom()); ts.add("a"); ts.add("bc"); ts.add("de"); ts.add("c"); ts.add("d"); ts.add("f"); for(Iterator it = ts.iterator();it.hasNext(); ){ System.out.println(it.next()); } } } /* 在写排序算法时,注意重复元素处理! */