天天看點

面試官:說一下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 内部的實作接口截圖:

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

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

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

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

4. Comparable 和 Comparator 差別

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

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

咳咳,不要慌...

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

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

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

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

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

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

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

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

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

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

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

通過上面 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 方式

代碼及執行截圖:

面試官:說一下List排序方法
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; // 倒序
    }
}
           

然後我們測試一下:

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

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);
           

執行結果如下:

面試官:說一下List排序方法
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

執行截圖:

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

繼續閱讀