淺談 Java 自定義排序之 Comparator

  排序是編程中常常須要用到的功能,而 Java 的工具類 Collections 中也提供了 sort 方法用於實現對列表等集合中元素的排序。Collections.sort() 方法有兩種形式:Collections.sort(List)Collections.sort(List, Comparator)java

  第一種 Collections.sort(List) 要求 List 中的元素已經實現了 Comparable 接口,第二種 Collections.sort(List, Comparator) 則須要實現一個比較器。基於比較的排序的關鍵就是能比較兩個元素的大小,知道了誰大誰小,才能肯定誰排在前面誰排在後面;而這兩種方法的本質都是爲了肯定兩個元素誰大誰小。接下來主要談一談基於比較器的自定義排序。編程

  先看個排序示例:工具

public static void main(String[] args) {
	Integer[] input = { 1, 3, 8, 7, 4, 9, 2 };        
	List<Integer> lst = Arrays.asList(input);
	
	Collections.sort(lst);
	System.out.println(lst);
}
//輸出爲: [1, 2, 3, 4, 7, 8, 9]

  能夠看到,本來無序的列表變成了從小到大排列。緣由有二:code

  1. Integer 類實現了 Comparable 接口,使得元素之間能夠比較大小
  2. sort 方法默認是從小到大排列(這點很是重要)

  然而大多數狀況下,咱們想要的都不是簡單的升序排列,這時候自定義排序就要派上用場了。Comparator 實現自定義排序的關鍵是實現 compare 方法,該方法聲明爲:排序

int compare(T o1, T o2);

當方法返回負值時,表明 o1 < o2;當方法返回 0 時,表明 o1 = o2;當方法返回正值時,表明 o1 > o2;下面以實現降序排列爲例,演示如何使用 Comparator。接口

###1、降序排列input

public class Main {
    public static void main(String[] args) {
        Integer[] input = { 1, 3, 8, 7, 4, 9, 2 };        
        List<Integer> lst = Arrays.asList(input);
        
        Collections.sort(lst, new IntComparator<Integer>());
        System.out.println(lst);
    }
}

class IntComparator<T> implements Comparator<T> {
    public int compare(T a, T b) {
        return (Integer)b - (Integer)a;
    }
}
//輸出爲: [9, 8, 7, 4, 3, 2, 1]

  爲何這樣就實現了降序排列呢?io

  這是由於當傳入 Comparator 參數時, sort 方法會將須要比較大小的兩個元素 a,b 做爲參數傳給 Comparator.compare(T a, T b) 方法,根據返回的結果判斷 a,b 的大小。例如,傳入1 和 3 的時候,compare 返回 2,正值表明 a > b,即 1 「大於」 3,這個「大於」正是咱們本身定義的規則。而後,根據 sort 方法默認從小到大排序的性質,小的排在前面,因此最後 3 排在 1 前面,也就實現了降序排列。class

  在這裏 return (Integer)b - (Integer)a; 是一種經驗寫法,若是分解開來應該是這樣:List

class IntComparator<T> implements Comparator<T> {
    public int compare(T a, T b) {
        int num1 = (Integer)a;
        int num2 = (Integer)b;
        
        if(num1 > num2) { //若是 a>b,根據自定義規則 a 應該在前面,即自定義規則中 a 「小於」 b,故此時返回負值
            return -1;
        } else if(num1 < num2) {
            return 1;
        } else {
            return 0;
        }
    }
}

  該 compare 方法很是簡單,但在實際應用中,因爲自定義規則的複雜性,compare 的編寫難度也可能變得很大。下面再舉一例,讓你們加深對 compare 的理解。

###2、奇偶排列   要求:奇數排在偶數前面,奇數之間從小到大排列,偶數之間從大到小排序

class IntComparator<T> implements Comparator<T> {
    public int compare(T a, T b) {
        int num1 = (Integer)a;
        int num2 = (Integer)b;
        if(num1 % 2 == 1 && num2 % 2 == 1) {
            return num1 - num2; // ①
        } else if(num1 % 2 == 0 && num2 % 2 == 0) {
            return num2 - num1; // ②
        } else if(num1 % 2 == 1 && num2 % 2 == 0) {
            return -1; // ③
        } else {
            return 1; // ④
        }
    }
}

  ① ② 表示兩數同奇或同偶的狀況,此時根據經驗寫法很容易獲得。

  ③ ④ 表示奇偶不一樣的狀況,此時若 a 爲奇數,b 爲偶數,則 a 應該排在 b 前面,即 a 「小於」 b,故返回負值;反之,返回正值。

  最後,再次強調:排在前面的元素「小」,排在後面的元素「大」

  留個練習,有興趣的朋友能夠作下,看看本身是否是真的掌握了。

  練習題:實現數字按照高位到低位的比較,進行降序排序;高位相同的,位數少的排前面。例如:輸入 {3, 34, 5, 7, 56, 523, 52, 571};輸出 {7, 5, 571, 56, 52, 523, 3, 34}

相關文章
相關標籤/搜索