面試官:說一下List排序方法


1. 前言

排序算是比較高頻的面試題了,節前面試了的兩家公司都有問到排序問題,整理后分享給大家(文末見總結)。

通常我們想到實現排序就是 Collections 工具類的 sort() 方法,而 sort() 方法有兩種:

  1. 直接調用 Collections.sort(List list) 方法進行排序(正序排序)。

  2. 調用 Collections.sort(List list,Comparator<? super T> c) ,自定義實現 Comparator 接口,重新 compareTo 方法。(相當於指定排序規則)

下面來詳細說明這兩個方法。

2. 什么是 Comparator ?

在看方法之前,我們先來看看這個 Comparator 到底有什么用?

Comparator ,中文意思為「比較器」,比較器的出現就是有些自定義類的 List 集合,不支持自身比較或者自身比較函數不能滿足需求時,然后就可以寫一個比較器來完成兩個對象大小之間的比較,上邊提到的方法 2 就是指定使用自定義 Comparator 來實現比較;而方法 1 是不指定 Comparator,不指定就會使用默認的排序方式(正序)。

3. List 屬性的不同

List 排序一般分為「單屬性排序」以及「實體屬性排序」,單屬性就是像是 String、Integer 等封裝類(List list,List list),這些基本類型的封裝類都已經實現了 Comparable 接口,並重寫 compareTo() 方法,實體屬性則就是我們自定義的實體類,然后想通過某些屬性對象進行排序。

單屬性

我們拿 Integer 類為例:

List<Integer> list = new ArrayList<Integer>();

如下為 Integer 內部的實現接口截圖:

所以,當我們直接調用 Collections.sort() 方法就可以實現排序效果(正序),舉例說明:

這就是單屬性集合的排序,直接調用 Collections.sort() 接口就能完成排序。

4. Comparable 和 Comparator 區別

然后就可能有小伙伴說,哎?你不對勁...

你上邊說的是 Comparator 比較器,現在怎么 Integer 實現的是 Comparable 接口?Comparable 又是個什么鬼,這倆單詞怎么長的這么像... 跟 Comparator 到底有啥區別呀?

咳咳,不要慌...

其實我們可以先看一下 Comparable 接口,該接口內部就只有一個 compareTo() 方法:

再來看看 Comparator 接口,Comparator 接口的內部方法就比較多了,當然,在這我們就關注一下 compare() 方法即可:

我們再回到 Integer 類,Integer 實現了 Comparable 接口,所以我們找一下 compareTo() 方法如下:

如上方法,compareTo() 方法內部調用了 Integer 內部的 compare() 方法,通過注釋我們發現。

Integer 內部完成了數值的比較?

其實到這也有點眉目了,好多文章有這么一個說法:Comparable 屬於內比較器,Comparator 屬於外比較器

所謂的內比較器,我們還是以 Integer 為例,Integer 實現了 Comparable 接口,從 Integer 內部完成了數值的比較,也就是拿另外一個值跟自身比。

所謂的外比較器,就是他會拿一個單獨的類來完成比較,這個時候我們就可以拿方法二來看了:

通過上面 List 的例子我們了解到了 Comparator 跟 Comparable 的使用,使用這兩種方式都可以完成單屬性的排序,區別就是內外部實現不同。

排序規則:

o1大於o2,返回正整數

o1等於o2,返回0

o1小於o3,返回負整數

5. 實體屬性排序

因為平時工作中還是以實體屬性 List 排序為主,並不會是直接 List,所以下面我們就通過一個 List 例子來分別通過 Comparator、Comparable 實現排序。

User.java

public class User {
  /**用戶年齡**/
    private Integer age;

    public User(Integer age){
        this.age = age;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
5.1 Comparator 方式

代碼及執行截圖:

5.2 Comparable 方式

我們需要讓 User.java 實體實現一個 Comparable 接口,並重寫 compareTo() 方法:

public class User implements Comparable<User>{

    private Integer age;

    public User(Integer age){
        this.age = age;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    @Override
    public int compareTo(User o) {
        // return this.age - o.getAge(); 正序
        return o.getAge() - this.age; // 倒序
    }
}

然后我們測試一下:

ok,到這我們就實現了兩種方式完成對實體屬性對象的集合進行排序。

6. 總結

實現排序有兩種方式:

  • 對象內部實現 Comparable 接口,重新 compareTo() 方法(區分正序倒序),完成內部比較,然后調用 Collections.sort() 排序。

  • 新建一個實現了 Comparator 接口的類,並重寫 compare() 抽象方法

如下轉自:https://my.oschina.net/sdlvzg/blog/2243766

JDK1.8之后可以很方便的對 List 進行排序,不用再寫 Collections 類了。

6.1 基礎類型 List 排序
/* 對數字進行排序 */
List<Integer> nums = Arrays.asList(3,1,5,2,9,8,4,10,6,7);
nums.sort(Comparator.reverseOrder()); /* reverseOrder倒序 */
System.err.println("倒序:"+nums);

nums.sort(Comparator.naturalOrder()); /* naturalOrder自然排序即:正序 */
System.err.println("正序:"+nums);

執行結果如下:

6.2 對象List單屬性排序
List<User> listDevs = new ArrayList<User>(){{
    add(new User(10));
    add(new User(9));
    add(new User(20));
    add(new User(4));
}};

System.out.println("排序前:");
/*JAVA8的寫法,循環*/
listDevs.forEach((developer)->System.out.println(developer.getAge()));

/*第一個寫法*/
Collections.sort(listDevs, new Comparator<User>() {
    @Override
    public int compare(User o1, User o2) {
        return o1.getAge().compareTo(o2.getAge());
    }
});
/*第二個寫法,JAVA8的寫法,List 接口支持直接使用 sort 該方法,不再需要使用 Collections.sort 了
listDevs.sort(listDevs, new Comparator<Developer>() {
   @Override
   public int compare(Developer o1, Developer o2) {
       return o1.getAge().compareTo(o2.getAge();
   }
});*/

/*第三個寫法,Lambda寫法,JAVA8的寫法
listDevs.sort((Developer o1, Developer o2)->o1.getAge().compareTo(o2.getAge()));*/

/*第四個寫法,Lambda寫法,JAVA8的寫法
listDevs.sort((o1, o2)->o1.getAge().compareTo(o2.getAge()));*/

/*第五寫法,個Lambda寫法,JAVA8的寫法
listDevs.sort(Comparator.comparing(Developer::getAge));*/

/*第六寫法,個Lambda寫法,JAVA8的寫法*/
Comparator<User> ageComparator = (o1, o2)->o1.getAge().compareTo(o2.getAge());
listDevs.sort(ageComparator);       /*按上面配置的順序取值*/
listDevs.sort(ageComparator.reversed());    /*按上面配置的順序反向取值*/

System.out.println("排序后:");
/*JAVA8的寫法,循環*/
listDevs.forEach((developer)->System.out.println(developer.getAge()));

博客園持續更新:https://www.cnblogs.com/niceyoo

執行截圖:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM