zoukankan      html  css  js  c++  java
  • [改善Java代码]非稳定排序推荐使用List

    我们知道Set与List的最大区别就是Set中的元素不可以重复(这个重复指的equals方法的返回值相等),其他方面则没有太大的区别了,在Set的实现类中有一个比较常用的类需要了解一下:TreeSet,该类实现了类默认排序为升序的Set集合,如果插入一个元素,默认会按照升序排列(当然是根据Comparable接口的compareTo的返回值确定排序位置了),不过,这样的排序是不是在元素经常变化的场景中也适用呢?我们来看例子:

     1 import java.util.SortedSet;
     2 import java.util.TreeSet;
     3 
     4 public class Client {
     5     public static void main(String[] args) {
     6         SortedSet<Person> set = new TreeSet<Person>();
     7         //身高180CM
     8         set.add(new Person(180));
     9         //身高175CM
    10         set.add(new Person(175));
    11         
    12         for(Person p:set){
    13             System.out.println("身高:"+p.getHeight());
    14         }
    15     }
    16     
    17     static class Person implements Comparable<Person>{
    18         //身高
    19         private int height;
    20         
    21         public Person(int _age){
    22             height = _age;
    23         }
    24         
    25 
    26         public int getHeight() {
    27             return height;
    28         }
    29 
    30 
    31         public void setHeight(int height) {
    32             this.height = height;
    33         }
    34 
    35         //按照身高排序
    36         public int compareTo(Person o) {
    37             return height - o.height;
    38         }
    39 
    40     }
    41 }

    程序输出:

    身高:175
    身高:180

    这没有问题,随着时间的推移,身高175cm的人长高了10cm,而180cm却保持不变,那排序的位置应该改变一下吧,看代码(只需修改main方法):

     1     public static void main(String[] args) {
     2         SortedSet<Person> set = new TreeSet<Person>();
     3         // 身高180CM
     4         set.add(new Person(180));
     5         // 身高175CM
     6         set.add(new Person(175));
     7         // 身高最矮的人大变身
     8         set.first().setHeight(185);
     9         for (Person p : set) {
    10             System.out.println("身高:" + p.getHeight());
    11         }
    12     }

    程序输出:

    身高:185
    身高:180

    很可惜,竟然没有重新排序,偏离了我们的预期。这正是下面要说明的问题,SortedSet接口(TreeSet实现了该接口)只是定义了在给集合加入元素时将其进行排序,并不能保证元素修改后的排序结果,因此TreeSet使用于不变量的集合数据排序,比如String、Integer等类型,但不适用于可变量的排序,特别是不确定何时元素会发生变化的数据集合。 
    原因知道了,那如何解决此类重排序问题呢?有两种方式: 

    (1).Set集合重排序 
    重新生成一个Set对象,也就是对原有的Set对象重排序,代码如下:

     1 import java.util.ArrayList;
     2 import java.util.SortedSet;
     3 import java.util.TreeSet;
     4 
     5 public class Client {
     6     public static void main(String[] args) {
     7         SortedSet<Person> set = new TreeSet<Person>();
     8         // 身高180CM
     9         set.add(new Person(180));
    10         // 身高175CM
    11         set.add(new Person(175));
    12         // 身高最矮的人大变身
    13         set.first().setHeight(185);
    14         //set重排序
    15         set = new TreeSet<Person>(new ArrayList<Person>(set));
           //set = new TreeSet(set);该构造函数只是原Set的浅拷贝,如果里面有相同的元素,是不会重新排序的
    16 for (Person p : set) { 17 System.out.println("身高:" + p.getHeight()); 18 } 19 } 20 21 static class Person implements Comparable<Person> { 22 // 身高 23 private int height; 24 25 public Person(int _age) { 26 height = _age; 27 } 28 29 public int getHeight() { 30 return height; 31 } 32 33 public void setHeight(int height) { 34 this.height = height; 35 } 36 37 // 按照身高排序 38 public int compareTo(Person o) { 39 return height - o.height; 40 } 41 42 } 43 }

    程序输出:

    身高:180
    身高:185

    就一句话即可重新排序。可能有读者会问,使用TreeSet(SortedSet< E > s)这个构造函数不是可以更好地解决问题吗?不行,该构造函数只是原Set的浅拷贝,如果里面有相同的元素,是不会重新排序的。 
    (2).彻底重构掉TreeSet,使用List解决问题 
    我们之所以使用TreeSet是希望实现自动排序,即使修改也能自动排序,既然它无法实现,那就用List来代替,然后再使用Collections.sort()方法对List排序.看代码:

     1 import java.util.ArrayList;
     2 import java.util.Collections;
     3 import java.util.List;
     4 import java.util.TreeSet;
     5 
     6 public class Client {
     7     public static void main(String[] args) {
     8         List<Person> list = new ArrayList<Person>();
     9         // 身高180CM
    10         list.add(new Person(180));
    11         // 身高175CM
    12         list.add(new Person(175));
    13         // 身高最矮的人大变身
    14         list.get(1).setHeight(185);
    15         
    16         //排序
    17         Collections.sort(list);
    18         for (Person p : list) {
    19             System.out.println("身高:" + p.getHeight());
    20         }
    21     }
    22 
    23     static class Person implements Comparable<Person> {
    24         // 身高
    25         private int height;
    26 
    27         public Person(int _age) {
    28             height = _age;
    29         }
    30 
    31         public int getHeight() {
    32             return height;
    33         }
    34 
    35         public void setHeight(int height) {
    36             this.height = height;
    37         }
    38 
    39         // 按照身高排序
    40         public int compareTo(Person o) {
    41             return height - o.height;
    42         }
    43 
    44     }
    45 }

    程序输出:

    身高:180
    身高:185

    两种方法都可以解决我们的困境,到底哪一个是最优的呢?对于不变量的排序,例如直接量(也就是8个基本类型)、String类型等,推荐使用TreeSet,而对于可变量,例如我们自己写的类,可能会在逻辑处理中改变其排序关键值的,则建议使用List自行排序。 
    又有问题了,如果需要保证集合中元素的唯一性,又要保证元素值修改后排序正确,那该如何处理呢?List不能保证集合中的元素唯一,它是可以重复的,而Set能保证元素唯一,不重复。如果采用List解决排序问题,就需要自行解决元素重复问题(若要剔除也很简单,转变为HashSet,剔除后再转回来)。若采用TreeSet,则需要解决元素修改后的排序问题,孰是孰非,就需要根据具体的开发场景来决定了。

  • 相关阅读:
    ios--->cell里面 self 和self.contentview的区别
    ios--->tableView的估算高度的作用
    ios--->泛型
    ios--->上下拉刷新控件MJRefresh
    ios--->NSNotificationCenter传值
    ios--->ios消息机制(NSNotification 和 NSNotificationCenter)
    ios--->self.view.window在逻辑判断中的作用
    ios--->ios == 和 isEqual的用法区别
    序号 斑马线显示表格的代码
    vim 显示行号
  • 原文地址:https://www.cnblogs.com/DreamDrive/p/5660201.html
Copyright © 2011-2022 走看看