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

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测试类

package list_set;
import java.util.Iterator;
import java.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());//自然排序
//         return this.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测试类

package list_set;
import java.util.Comparator;
import java.util.Iterator;
import java.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)代码

package list_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测试代码

package list_set;
 
import java.util.Iterator;
import java.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)字符串长度比较器
package list_set;
 
import java.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)字符串长度排序测试

package list_set;
import java.util.Iterator;
import java.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集合排序规则的分析

      存的方式,从二叉树的根节点出发,进行比对,如果小于根节点的值,则放在左子树这边;如果大于根节点的值,则放在右子树这边;否则值与根节点相同,则不进行存储

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

     说明:左子树,父节点,右子树三者的关系  左子树 < 父节点 <右子树

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值