Set集合TreeSet学习(Set集合学习二)

来源:互联网 发布:mac顶部菜单栏截图工具 编辑:程序博客网 时间:2024/06/08 11:30

Set集合TreeSet学习(Set集合学习二)


4、TreeSet: 可以对Set集合中的元素进行排序。是不同步的


4.1、TreeSet保证元素唯一的方式

TreeSet使用元素的自然顺序(字典顺序)对元素进行排序【TreeSet集合排序方式一:让元素自身具备比较功能】

或者

根据创建 set 时提供的 Comparator (比较器)进行排序,具体取决于使用的构造方法。【TreeSet集合排序方式二:让集合自身具备比较功能】

判断元素唯一性的方式:就是根据比较方法的返回结果是否是0,是0,就是相同元素,不存。

(1)TreeSet集合排序方式一:让元素自身具备比较功能

让元素自身具备比较功能,只就需要实现Comparable接口。覆盖compareTo方法。【Comparable接口的compareTo方法】

即:自定义对象实现Comparable接口,定义排序方式,实现comparaTo方法。

(2)特殊场景分析

场景:

如果不要按照对象中具备的自然顺序进行排序,怎么办?

对象不是自己的定义的,而是使用别人定义好的,我们不能对这个对象做任何修改,而且这个对象没有实现Comparable接口,怎么办?

这个对象不具有比较性!或者说,这个对象具备比较性,实现了Comparable接口,但是这个对象具备的比较性,不是我们需要的,我们该怎么办?

解决方案:

使用TreeSet集合排序方式二:让集合自身具备比较功能

(3)TreeSet集合排序方式二:让集合自身具备比较功能

让集合自身具备比较功能,定义一个类实现Comparator接口,覆盖compare方法。将该类对象作为参数传递给TreeSet集合的构造函数。

4.2、TreeSet集合使用注意

(1)TreeSet集合排序方式一:让元素自身具备比较功能

【1】当元素为自定义对象(eg:Person类)时,让元素自身具备比较功能,实现Comparable接口,覆盖compareTo方法

 

【2】当元素为字符串对象(eg:“abd”)或者jdk中的对象有实现Comparable接口的方法时,由于这些对象本身已经实现了Comparable接口的compareTo方法,本身就具备比较功能,直接使用TreeSet即可。

 

(2)TreeSet集合排序方式二:让集合自身具备比较功能

集合自身具备比较功能,定义一个类实现Comparator接口,覆盖compare方法。将该类对象作为参数传递给TreeSet集合的构造函数。

public TreeSet(Comparator<? super E>comparator)构造时传递参数

构造一个新的空 TreeSet,它根据指定比较器进行排序。插入到该 set 的所有元素都必须能够由指定比较器进行相互比较:对于 set 中的任意两个元素 e1 和 e2,执行 comparator.compare(e1, e2) 都不得抛出 ClassCastException

(3)排序优先

当TreeSet集合使用时,如果元素本身具备比较功能

然后又定义一个类实现Comparator接口,覆盖compare方法,并该类对象作为参数传递给TreeSet集合的构造函数。使得TreeSet集合自身具备比较功能

这时候,TreeSet的排序方法以集合自身具备的比较功能为主(即:TreeSet集合排序方式二为主,忽略TreeSet集合排序方式一)

结论:当TreeSet集合有两种比较功能时,TreeSet集合排序方式二(集合自身具备比较功能优先于 TreeSet集合排序方式一(元素本身具备比较功能

4.3、TreeSet集合排序案例

(1)TreeSet集合排序方式一案例:

让元素自身具备比较功能

代码实现:

【1】集合排序1测试类

packagelist_set;importjava.util.Iterator;importjava.util.TreeSet;/* * TreeSet集合排序方式一: * 让元素自身具备比较功能,就需要实现Comparable接口。覆盖compareTo方法。 */ public class TreeSetFirst {    public static void main(String[] args) {       TreeSet set=new TreeSet();             set.add(new Person("张三",23));             set.add(new Person("张三",23));//去除重复   让元素自身具备比较功能       set.add(new Person("李四",24));//去除重复              set.add(new Person("李四",24));       set.add(new Person("王五",24));       set.add(new Person("赵六",25));       set.add(new Person("你好",26));             //遍历       for(Iterator it=set.iterator();it.hasNext();){           Person p=(Person)it.next();           System.out.println(p.getName()+":"+p.getAge());       }    }}

【2】Person自定义对象

/* * 让person元素本身具备比较功能 * 实现Comparable接口。覆盖compareTo方法。 */class Person implements Comparable{    private String name;    private int age;    public Person(String name, int age) {       super();       this.name = name;       this.age = age;    }    public String getName() {       return name;    }    public void setName(String name) {       this.name = name;    }    public int getAge() {       return age;    }    public void setAge(int age) {       this.age = age;    }    @Override    public int compareTo(Object o) {//定义比较方式       /*        *1.年纪小的排在前面        *2.当年纪相同是,名字的自然排序小于0的排在前面        */       Person p=(Person)o;       int ageCompare=this.getAge()-p.getAge();             if(ageCompare==0){           //小于0 在前;等于0 相等;大于0 在后           return this.getName().compareTo(p.getName());//自然排序//         returnthis.name.hashCode()-p.name.hashCode();//hashcode值       }            return ageCompare;//小于0 在前;大于0 在后    } }

结果:

张三:23

李四:24

王五:24

赵六:25

你好:26

(2)TreeSet集合排序方式二案例:

让集合自身具备比较功能

代码实现:

【1】自定义比较器

/* * 自定义比较器实现Comparator接口,覆盖compare方法。 */class MyComparator implements Comparator {     @Override    public int compare(Object o1, Object o2) {       /*        *1.年纪小的排在前面 2.当年纪相同是,名字的自然排序小于0的排在前面        */       Person p1 = (Person) o1;       Person p2 = (Person) o2;        int ageCompare = p1.getAge() - p2.getAge();        if (ageCompare == 0) {           return p1.getName().compareTo(p2.getName());//自然排序//         return p1.getName().hashCode() -p2.getName().hashCode();//hashcode值           // 小于0 在前;等于0相等;大于0在后       }      return ageCompare;// 小于0 在前;大于0 在后    } }

【2】集合排序2测试类

packagelist_set;importjava.util.Comparator;importjava.util.Iterator;importjava.util.TreeSet; /* * TreeSet集合排序方式二: * 让集合自身具备比较功能,定义一个类实现Comparator接口,覆盖compare方法。 * 将该类对象作为参数传递给TreeSet集合的构造函数。 */public class TreeSetSecond {    public static void main(String[] args) {       TreeSet set = new TreeSet(new MyComparator());//调用自定义比较器,让集合自身具备比较功能        set.add(new Person("张三", 23));        set.add(new Person("张三", 23));// 去除重复让集合自身具备比较功能       set.add(new Person("李四", 24));// 去除重复             set.add(new Person("李四", 24));       set.add(new Person("王五", 24));       set.add(new Person("赵六", 25));       set.add(new Person("你好", 26));        // 遍历       for (Iterator it = set.iterator(); it.hasNext();) {           Person p = (Person) it.next();           System.out.println(p.getName() + ":" + p.getAge());       }    }}

结果:

张三:23

李四:24

王五:24

赵六:25

你好:26

4.4、TreeSet集合排序规则的分析

参考博客园

博文:Java深入了解TreeSet

地址:http://www.cnblogs.com/yzssoft/p/7127894.html

(1)代码

packagelist_set; /* * 让person元素本身具备比较功能 * 实现Comparable接口。覆盖compareTo方法。 */class Persons implements Comparable {    private String name;    private int age;    public Persons(String name, int age) {       super();       this.name = name;       this.age = age;    }    public String getName() {       return name;    }    public void setName(String name) {       this.name = name;    }    public int getAge() {       return age;    }    public void setAge(int age) {       this.age = age;    }    @Override    public int compareTo(Object o) {// 定义比较方式             return 0; // 当compareTo方法返回0的时候集合中只有一个元素//     return 1; // 当compareTo方法返回正数的时候集合会怎么存就怎么取//     return -1; // 当compareTo方法返回负数的时候集合会倒序存储    } }

(2)代码现象分析

为什么返回0,只会存一个元素,返回-1会倒序存储,返回1会怎么存就怎么取呢?

原因:在于TreeSet底层其实是一个二叉树机构,且每插入一个新元素(第一个除外)都会调用compareTo()的方法去和上一个插入的元素作比较,并按二叉树的结构进行排列。

1. 如果将compareTo()方法的返回值固定为0,元素值每次比较,都认为是相同的元素,这时就不再向TreeSet中插入除第一个外的新元素。所以TreeSet中就只存在插入的第一个元素。

2. 如果将compareTo()方法的返回值固定为1,元素值每次比较,都认为新插入的元素比上一个元素大,于是二叉树存储时,会存在根的右侧,读取时就是正序排列的。

3. 如果将compareTo()方法的返回值固定为-1,元素值每次比较,都认为新插入的元素比上一个元素小,于是二叉树存储时,会存在根的左侧,读取时就是倒序排列的。

(3)结论

同理,Comparator(比较器)的compare方法返回结果和Comparable接口的compareTo方法返回结果的正负情况,决定了TreeSet集合的排序情况

返回结果为正数时,当前元素,比上一个元素大

返回结果为负数时,当前元素,比上一个元素小

返回结果为0时,当前元素和上一个元素相同。

(4)三种情况案例

1情况一:CompareTo方法中,直接返回return 0(集合只有一个元素)

1.1compareTo方法

public int compareTo(Object o) {// 定义比较方式       return 0; // 当compareTo方法返回0的时候集合中只有一个元素}

1.2测试代码

packagelist_set; importjava.util.Iterator;importjava.util.TreeSet; public class Test1 {     public static void main(String[] args) {       TreeSet set=new TreeSet();       set.add(new Persons("张三",23));                    set.add(new Persons("李四",24));       set.add(new Persons("王五",24));       set.add(new Persons("赵六",25));       set.add(new Persons("你好",26));             //遍历       for(Iterator it=set.iterator();it.hasNext();){           Persons p=(Persons)it.next();           System.out.println(p.getName()+":"+p.getAge());       }          } }

1.3结果【只有一个元素】

张三:23


2 情况二:CompareTo方法中,直接返回return 1(集合正序排列)

2.1compareTo方法

    public int compareTo(Object o) {// 定义比较方式       return 1; // 当compareTo方法返回正数的时候集合会怎么存就怎么取    }

2.2测试代码

同:三种情况案例的情况一中的4.1.2测试代码

2.3结果【正序输出】

张三:23

李四:24

王五:24

赵六:25

你好:26

 

3 情况三:CompareTo方法中,直接返回return -1(集合逆序排列)

3.1compareTo方法

public intcompareTo(Object o) {// 定义比较方式       return -1; // 当compareTo方法返回负数的时候集合会倒序存储    }

3.2测试代码

同:三种情况案例的情况一中的4.1.2测试代码

3.3结果【逆序输出】

你好:26

赵六:25

王五:24

李四:24

张三:23

4.5、应用:对字符串进行长度排序

(1)字符串长度比较器

packagelist_set; importjava.util.Comparator;/* * 字符串长度比较器 */public class ComparatorByLength implements Comparator {     @Override    public int compare(Object o1, Object o2) {       //1.先比较字符串长度,如果长度不同,则比较结束,否则,进入2       //2.比较字符串的字典顺序       String s1=(String)o1;       String s2=(String)o2;             int temp=s1.length()-s2.length();             return temp==0?s1.compareTo(s2):temp;    } }

(2)字符串长度排序测试

packagelist_set;importjava.util.Iterator;importjava.util.TreeSet;/* * 对字符串进行长度排序 */public class CompareByLengthTest {    public static void main(String[] args) {        TreeSetts = new TreeSet(new ComparatorByLength());//字符串长度排序比较器        ts.add("aaaaa");       ts.add("zz");       ts.add("nbaq");       ts.add("cba");       ts.add("abc");             Iterator it = ts.iterator();             while(it.hasNext()){           System.out.println(it.next());       }    } }

(3)结果

zz

abc

cba

nbaq

aaaaa

 

 

4.6思考:TreeSet怎么存进去?怎么取出来?

存:按照TreeSet的两种排序方式的其中一种进行排序,详情看:TreeSet集合排序规则的分析

 

取:从二叉树的最左端的开始取,然后按照【左子树,右子树,父节点】顺序进行取元素。依次类推,进行取,直到结束

 

原创粉丝点击