zoukankan      html  css  js  c++  java
  • Java——(四)Collection之Set集合TreeSet类

     ------Java培训、Android培训、iOS培训、.Net培训、期待与您交流! -------

    TreeSet类

      TreeSet是SortedSet接口的实现类,正如SortedSet名字所暗示的,TreeSet可以确保集合

    元素处于排序状态。与HashSet集合相比,TreeSet还提供了如下几个额外的方法。

    1)Comparator comparator():

    2)Object first():

    3)Object last():

    4)Object lower(Object o):

    5)Object higher(Object 0):

    6)SortedSet subSet(fromElemnet, toElement):

    7)SortedSet headSet(toElement):返回此Set的子集,由小于toElement的元素组成。

    8)SortedSet tailSet(fromElement):返回此Set的子集,由大于或等于fromElement的元素组成。

    下面出现测试了TreeSet的通用用法:

     1 import java.util.TreeSet;
     2 
     3 
     4 public class TreeSetTest {
     5 
     6     public static void main(String[] args) {
     7         
     8         TreeSet numsSet = new TreeSet<>();
     9         //向TreeSet中添加四个Integer对象
    10         numsSet.add(5);
    11         numsSet.add(2);
    12         numsSet.add(10);
    13         numsSet.add(-2);
    14         //输出集合元素,看到集合元素已经处于排序状态
    15         System.out.println(numsSet);
    16         //输出集合里的第一个元素
    17         System.out.println(numsSet.first());
    18         //输出集合里的最后一个元素
    19         System.out.println(numsSet.last());
    20         //返回小于4的子集,不包含4
    21         System.out.println(numsSet.headSet(4));
    22         //返回大于5的子集,如果、set中包含5,子集中也包含5
    23         System.out.println(numsSet.tailSet(5));
    24         //返回大于等于-3、小于4的子集
    25         System.out.println(numsSet.subSet(-3, 4));
    26     }
    27 
    28 }

    运行结果:

    [-2, 2, 5, 10]
    -2
    10
    [-2, 2]
    [5, 10]
    [-2, 2]

      与HashSet集合采用hash算法来决定因素的存储位置不同,TreeSet采用红黑树的数据结构

    来存储集合元素。TreeSet支持两种排序方法:自然排序和定制排序。默认情况下采用自然排序。

    1.自然排序

      TreeSet会调用集合元素的Comparable接口中的compareTo(Object obj)方法来比较元素

    之间的大小关系,然后将集合元素按升序排列。当一个对象调用该方法与另一个对象进行比较时,

    例如obj1.compareTo(obj2),如果该方法返回0,则表明这两个对象相等;如果该方法返回一个

    正数,则表明obj1大于obj2;如果该方法返回一个负数,则表明obj1小于obj2.

    下面是实现了Comparable接口的常用类:

    BigDecimal、BigInteger以及所有的数值型对应的包装类:按它们对应的数值大小进行比较。

    • Character:按字符的UNICODE值进行比较。
    • Boolean:true对应的包装类实例大于false对应的包装类实例。
    • String:按字符串中的字符UNICODE值进行比较。
    • Date、Time:后面的时间、日期比前面的时间、日期大。

      如果试图把一个对象添加到TreeSet时,则该对象的类必须实现Comparable接口,否则则程

    序将会抛出异常。下面程序师范了这个错误。

     1 import java.util.TreeSet;
     2 
     3 class Err{
     4     
     5 }
     6 
     7 public class TreeSetErrorTest {
     8 
     9     public static void main(String[] args) {
    10 
    11         TreeSet tSet =new TreeSet<>();
    12         //向TreeSet集合中添加两个Err对象
    13         tSet.add(new Err());
    14         tSet.add(new Err());
    15     }
    16 
    17 }

    运行结果:

    1 Exception in thread "main" java.lang.ClassCastException: Err cannot be cast to java.lang.Comparable
    2     at java.util.TreeMap.compare(Unknown Source)
    3     at java.util.TreeMap.put(Unknown Source)
    4     at java.util.TreeSet.add(Unknown Source)
    5     at TreeSetErrorTest.main(TreeSetErrorTest.java:13)

      上面程序试图向TreeSet集合中添加两个Err对象,添加第一个对象时,TreeSet里没有任何

    因素,所以不会出现任何问题;当添加第二个Err对象时,TreeSet就会调用该对象的

    ComparaTo(Object obj)方法与集合中的其他因素进行比较——如果其对应的类没有实现

    Comparable接口则会引发ClassCastException异常。因此。上面程序将会在添加第二个对象的

    时候引发该异常。当试图从TreeSet中取出因素时,由于第一个元素没有实现Comparable接口,

    因此也会引发ClassCastException异常。

      大部分类在实现compareTo(Object obj)方法时,都需要将比较对象obj强制转换成相同类型

    ,因为只有相同类型的两个实例次啊会比较大小。当试图把一个对象添加到TreeSet集合时,

    TreeSet会调用该对象的compareTo(Object obj)方法与集合中的其他因素进行比较——这就是要

    求集合中的其他因素与该因素时同一个类的实例。也就是说,向TreeSet中添加的应该是同一个类

    的对象,否则也会引发ClassCastException异常。

    下面程序示范了这个错误。

     1 import java.util.Date;
     2 import java.util.TreeSet;
     3 
     4 
     5 public class TreeSetErrorTest2 {
     6 
     7     public static void main(String[] args) {
     8 
     9         TreeSet tSet = new TreeSet<>();
    10         tSet.add(new String("黑马程序员"));
    11         tSet.add(new Date());
    12     }
    13 
    14 }

    运行结果:

    Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.util.Date
        at java.util.Date.compareTo(Unknown Source)
        at java.util.TreeMap.put(Unknown Source)
        at java.util.TreeSet.add(Unknown Source)
        at TreeSetErrorTest2.main(TreeSetErrorTest2.java:11)

    上面程序先向TreeSet集合中添加了一个字符串对象,这个操作完全正确。当添加第二个Date对

    象时,TreeSet就会调用该对象的compareTo(Object obj)方法与集合中的其他因素进行比较

    ——Date对象的compareTo(Object obj)方法无法与字符串对象比较大小,所以上面程序将在

    添加Date对象时引发异常。

      如果是向TreeSet中添加的对象是程序员自定义类的对象,则可以向TreeSet中添加多种类型

    的对象,前提是用户自定义类实现了Comparable接口,实现该接口实现的compareTo(Object obj)

    方法没有进行强制类型转换。但当试图取出TreeSet里的集合数据时,不同类型的元素依然会发生

    ClassCastException异常。

      当把一个对象加入TreeSet集合中时,TreeSet调用该对象的compareTo(Object obj)方法与

    容器中的其他对象比较大小,然后根据红黑树结构找到它的存储位置。如果两个对象通过

    compareTo(Object obj)方法比较相等,新对象将无法添加到TreeSet集合中。他判断两个对象是否

    相等的唯一标准是:两个对象通过compareTo(Object obj)方法比较是否返回0——如果通过

    compareTo(Object obj)方法比较返回0,TreeSet则会认为它们相等;否则就认为它们不相等。

    示例:

     1 import java.util.TreeSet;
     2 
     3 
     4 class Z implements Comparable{
     5     int age;
     6     public Z(int age){
     7         this.age = age;
     8     }
     9     //重写equals()方法
    10     @Override
    11     public boolean equals(Object obj) {
    12 
    13         return true;
    14     }
    15     @Override
    16     public int compareTo(Object obj) {
    17 
    18         return 1;
    19     }
    20 }
    21 public class TreeSetTest2 {
    22 
    23     public static void main(String[] args) {
    24 
    25         TreeSet set = new TreeSet<>();
    26         Z z1 = new Z(6);
    27         set.add(z1);
    28         //输出true,表明添加成功
    29         System.out.println(set.add(z1));
    30         //输出set集合,将看到有两个变量
    31         System.out.println(set);
    32         //修改set集合的第一个元素的age变量
    33         ((Z)(set.first())).age = 9;
    34         //输出set集合的最后一个元素的age变量,将看到也变成了9
    35         System.out.println(((Z)(set.first())).age);
    36     }
    37 
    38 }

    运行结果:

    true
    [Z@717e5fde, Z@717e5fde]
    9

      程序中把同一对象再次添加到TreeSet集合中,因为z1对象的compareTo(Object obj)方法

    总是返回1,虽然它的equals()方法总是返回true,但TreeSet会认为z1对象和它自己也不相等,

    因此TreeSet可以添加两个z1对象。下图显示了TreeSet及Z对象在内存中的存储示意图。

    从图中可以看到TreeSet对象保存的两个对象,实际上是同一元素。

    如果把重写的compareTo(Object obj)方法中的返回值改为1,则运行结果如下:

    false
    [Z@39fc0f04]
    9

    如果向TreeSet中添加一个可变对象后,并且后面程序修改了该可变对象的Field,这将导致它与

    其他对象的大小顺序发生了改变,但TreeSet不会再次调整它们的顺序,甚至可能导致TreeSet

    中保存的这两个对象通过compareTo(Object obj)方法比较返回0.下面程序演示了这种情况。

     1 import java.util.TreeSet;
     2 
     3 class M implements Comparable {
     4 
     5     int count;
     6 
     7     public M(int count) {
     8         this.count = count;
     9     }
    10 
    11     @Override
    12     public String toString() {
    13 
    14         return "M[count:" + count + "]";
    15     }
    16     @Override
    17     public boolean equals(Object obj) {
    18 
    19         if (this == obj) {
    20             return true;
    21         }
    22         if (obj != null && obj.getClass() == M.class) {
    23             M m = (M)obj;
    24             if (m.count == this.count) {
    25                 return true;
    26             }
    27         }
    28         return false;
    29     }
    30     //重写compareTo()方法,根据count来比较大小
    31     @Override
    32     public int compareTo(Object obj) {
    33 
    34         M m = (M) obj;
    35         return count > m.count ? 1 : count < m.count ? -1 : 0;
    36     }
    37 
    38 }
    39 
    40 public class TreeSetTest3 {
    41 
    42     public static void main(String[] args) {
    43 
    44         TreeSet tsSet = new TreeSet<>();
    45         tsSet.add(new M(5));
    46         tsSet.add(new M(-3));
    47         tsSet.add(new M(9));
    48         tsSet.add(new M(-2));
    49         //打印TreeSet集合,集合元素是有序排列的
    50         System.out.println(tsSet);
    51         //取出第一个元素的count值
    52         M firstM = (M)tsSet.first();
    53         //对第一个元素赋值
    54         firstM.count = 20;
    55         //取出最后一个元素
    56         M lastM = (M)tsSet.last();
    57         //对最后一个元素的count值赋值,与第二个元素的count值相同
    58         lastM.count = -2;
    59         //输出可以看到TreeSet集合里的元素处于无序状态,且有重复元素
    60         System.out.println(tsSet);
    61         //删除Field被改变的元素,删除失败
    62         System.out.println(tsSet.remove(new M(-2)));
    63         System.out.println(tsSet);
    64         //删除field没有改变的元素,删除成功
    65         System.out.println(tsSet.remove(new M(5)));
    66         System.out.println(tsSet);
    67     }
    68 
    69 }

    运行结果:

    [M[count:-3], M[count:-2], M[count:5], M[count:9]]
    [M[count:20], M[count:-2], M[count:5], M[count:-2]]
    false
    [M[count:20], M[count:-2], M[count:5], M[count:-2]]
    true
    [M[count:20], M[count:-2], M[count:-2]]

         上面程序中的M对象对应的类正常重写了equals()方法和compareTo()方法,这两个方法都以M

    对象的count实例变量作为判断的依据。当改变TreeSet集合了可变元素的Field,再试图删除该对

    象时,TreeSet会删除失败,所以删除count为-2的M对象时,没有元素被删除;当删除count为5

    的M对象时,可以看到元素被删除,这表明TreeSet可以删除没有被修改的Field,且不与其他被修

    改Field的对象重复的对象。

    2.定制排序

      TreeSet的自然排序是根据集合元素的大小,TreeSet将它们一升序排序。如果需要实现定制

    排序,例如以降序排列,则可以通过Comparator接口的帮助。该接口里包含了一个int compare

    (T o1, T o2)方法,该方法用于比较o1和o2的大小:如果该方法返回正整数,则表明o1大于o2;

    如果该方法返回0,则表明o1等于o2;如果该方法返回负整数,则表明o1小于o2。

      实现定制排序,则需要在创建TreeSet集合对象时,提供一个Comparator对象与该TreeSet

    集合关联,由该Comparator对象负责集合元素的排序。

     1 import java.util.Comparator;
     2 import java.util.TreeSet;
     3 
     4 class C {
     5     int age;
     6 
     7     public C(int age) {
     8         this.age = age;
     9     }
    10 
    11     @Override
    12     public String toString() {
    13 
    14         return "C[age:" + age + "]";
    15     }
    16 }
    17 
    18 public class TreeSetTest4 {
    19 
    20     public static void main(String[] args) {
    21 
    22         TreeSet tSet = new TreeSet<>(new Comparator() {
    23             @Override
    24             public int compare(Object o1, Object o2) {
    25                 C c1 = (C) o1;
    26                 C c2 = (C) o2;
    27                 return c1.age > c2.age ? -1 : c1.age < c2.age ? 1 : 0;
    28             }
    29         });
    30         tSet.add(new C(5));
    31         tSet.add(new C(-3));
    32         tSet.add(new C(9));
    33         System.out.println(tSet);
    34     }
    35 
    36 }

    运行结果:

    [C[age:9], C[age:5], C[age:-3]]
  • 相关阅读:
    找不到方法 Void Newtonsoft.Json.JsonConvert.set_DefaultSettings
    HDUJ 1203 I NEED A OFFER!
    EasyUI基础入门之Resiable(可缩放)
    6大设计原则(2):里氏替换原则
    scikit-learn:class and function reference(看看你究竟掌握了多少。。)
    NoSQL之Redis探析
    docker 命令汇总2
    【Web应用-FTP】FTP 容量显示说明
    【Web应用-网络连接】关于 Azure Web 应用 4 分钟空闲连接的限制
    【Web应用-网络连接】Azure Web 应用对外连接数上限分析
  • 原文地址:https://www.cnblogs.com/xiongxuesong/p/4564375.html
Copyright © 2011-2022 走看看