Comparable與Comparator

Prerequisites:

由小到大 由大到小

假設有陣列如下:
1, 2, 3, 4, 5

由小到大

由小到大是指「目前位置」的值與「下一個位置」的值進行比較,比較方式是「目前位置」的值減「下一個位置」的值。

1, 2, 3, 4, 5 
↑  ↑
目 下
前 一
位 個
置 位
   置

1 - 2 = -1

傳回結果為-1,代表「目前位置」的值比「下一個位置」的值小,以氣泡排序來說,就不用交換。

氣泡排序

if (比較結果 > 0) {
  交換
}

假設陣列的值變成以下這樣。

2, 1, 3, 4, 5 
↑  ↑
目 下
前 一
位 個
置 位
   置

2 - 1 = 1

傳回結果為1,代表「目前位置」的值比「下一個位置」的值大,以氣泡排序來說,就要交換。

「目前位置」,如同下面程式碼的j,「下一個位置」,如同下面程式碼的j + 1,以下程式碼是「目前位置」的值 > 「下一個位置」的值,就交換。

1
2
3
if (arr[j] > arr[j + 1]) {
  // 交換
}

「目前位置」的值減「下一個位置」的值 > 0,等同於arr[j] > arr[j + 1],二者都是「目前位置」的值「大於」「下一個位置」的值,相減才會是正整數。

由大到小

比較方式是「下一個位置」的值減「目前位置」的值。

1, 2, 3, 4, 5 
↑  ↑
目 下
前 一
位 個
置 位
   置

「下一個位置」的值減「目前位置」的值
2 - 1 = 1

傳回結果為1,代表「下一個位置」的值比「目前位置」的值大,以氣泡排序來說,比較結果 > 0要交換。

氣泡排序

if (比較結果 > 0) {
  交換
}

交換之後變成下面這樣,2與1就完成由大到小排序。

2, 1, 3, 4, 5 

氣泡排序若要改成由大到小,以下的程式碼「大於>」要變「小於<」,代表「下一個位置j + 1 」的值比「目前位置 j 」的值大,就交換,由大到小,大的數字要在前面。

1
2
3
if (arr[j] < arr[j + 1]) {
  // 交換
}

Comparable介面

Comparable是一個介面,有一個compareTo()方法,功用是比較大小。

Comparable介面原始檔

1
2
3
public interface Comparable<T> {
    public int compareTo(T o);
}

compareTo(o)參數

每一個方法都有隱藏參數this,this就是「目前位置」物件,而o參數,是「下一個位置」的物件。

1, 2, 3, 4, 5 
↑  ↑
目 下
前 一
位 個
置 位
   置

比較

由小到大,this - o
由大到小,o - this

this是目前位置物件,o是下一個位置物件。

以下是由小到大。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class MyDate implements Comparable<MyDate> {
  private int year;
  private int mon;
  private int day;

  public MyDate(int year, int mon, int day) {
    this.year = year;
    this.mon = mon;
    this.day = day;
  }

  @Override
  public int compareTo(MyDate o) {
    // 由小到大 this - o
    int diff_y = this.year - o.year;
    // 不相等代表比較出結果,直接傳回比較結果
    // 之後的程式就沒必要再比較。
    if (diff_y != 0) {
      return diff_y;
    }

    int diff_m = this.mon - o.mon;
    if (diff_m != 0) {
      return diff_m;
    }

    int diff_day = this.day - o.day;
    if (diff_day != 0) {
      return diff_day;
    }
    return 0;
  }
}

比較日期大小

正數代表myDate > anotherDate
負數代表myDate < anotherDate
0代表myDate == anotherDate

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class Test {
  public static void main(String[] args) {
    MyDate myDate = new MyDate(2000, 11, 11);
    MyDate anotherDate = new MyDate(2000, 11, 5);
    int res = myDate.compareTo(anotherDate);
    System.out.println(res);
    System.out.println("==========");

    myDate = new MyDate(2000, 11, 1);
    anotherDate = new MyDate(2000, 11, 10);
    res = myDate.compareTo(anotherDate);
    System.out.println(res);
    System.out.println("==========");

    myDate = new MyDate(2000, 11, 11);
    anotherDate = new MyDate(2000, 11, 11);
    res = myDate.compareTo(anotherDate);
    System.out.println(res);
  }
}
6
==========
-9
==========
0

其它:泛型與Comparable

泛型介面的文章中,有提到實作泛型介面時要指定泛型類型,以下程式碼指定的泛型類型為MyDate,Intellij實作介面時會把MyDate的類型替代原本的T。

1
2
3
4
5
6
class MyDate implements Comparable<MyDate> {
  @Override
  public int compareTo(MyDate o) {
    return 0;
  }
}

Comparator

Comparator可以透過匿名類別Lambda,建立物件,只要實作比較的內容,就可單獨使用。

MyDate2提供getYear()、getMon()、getDay(),供其它類別使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
class MyDate2 {
  private int year;
  private int mon;
  private int day;

  public MyDate2(int year, int mon, int day) {
    this.year = year;
    this.mon = mon;
    this.day = day;
  }

  public int getYear() {
    return year;
  }

  public int getMon() {
    return mon;
  }

  public int getDay() {
    return day;
  }
}

Comparator.compare(o1,o2)

o1是「目前位置」物件,o2是「下一個位置」物件。

由小到大,o1 - o2
由大到小,o2 - o1

1, 2, 3, 4, 5 
↑  ↑
目 下
前 一
位 個
置 位
   置

比較日期大小

正數代表myDate2 > another
負數代表myDate2 < another
0代表myDate2 == another

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public class Test {
  public static void main(String[] args) {
    MyDate2 myDate2 = new MyDate2(2000, 11, 11);
    MyDate2 another = new MyDate2(2000, 11, 10);
    // 透過匿名類別建立物件
    Comparator<MyDate2> comparator = new Comparator<MyDate2>() {
      @Override
      public int compare(MyDate2 o1, MyDate2 o2) {
        // 由小到大,o1 - o2
        int diff_y = o1.getYear() - o2.getYear();
        if (diff_y != 0) {
          return diff_y;
        }

        int diff_m = o1.getMon() - o2.getMon();
        if (diff_m != 0) {
          return diff_m;
        }

        int diff_day = o1.getDay() - o2.getDay();
        if (diff_day != 0) {
          return diff_day;
        }
        return 0;
      }
    };
    int result = comparator.compare(myDate2, another);
    System.out.println(result);
  }
}
1

results matching ""

    No results matching ""