一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - Java中自然排序和比較器排序詳解

Java中自然排序和比較器排序詳解

2020-06-17 12:01daisy JAVA教程

這篇文章給大家介紹Java中的排序并不是指插入排序、希爾排序、歸并排序等具體的排序算法。而是自然排序和比較器排序,文中通過實例代碼介紹的很詳細,有需要的朋友們可以參考借鑒。

前言

當指執行插入排序、希爾排序、歸并排序等算法時,比較兩個對象“大小”的比較操作。我們很容易理解整型的 i>j 這樣的比較方式,但當我們對多個對象進行排序時,如何比較兩個對象的“大小”呢?這樣的比較 stu1 > stu2 顯然是不可能通過編譯的。為了解決如何比較兩個對象大小的問題,JDK提供了兩個接口 java.lang.Comparable java.util.Comparator

一、自然排序:java.lang.Comparable

Comparable 接口中只提供了一個方法: compareTo(Object obj) ,該方法的返回值是 int 。如果返回值為正數,則表示當前對象(調用該方法的對象)比 obj 對象“大”;反之“小”;如果為零的話,則表示兩對象相等。

下面是一個實現了 Comparable 接口的 Student 類:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public class Student implements Comparable {
 
 private int id;
  
 private String name;
 
 public Student() {
  super();
 }
 
 @Override
 public int compareTo(Object obj) {
  if (obj instanceof Student) {
   Student stu = (Student) obj;
   return id - stu.id;
  }
  return 0;
 }
 
 @Override
 public String toString() {
  return "<" + id + ", " + name + ">";
 }
}

Student 實現了自然排序接口 Comparable ,那么我們是怎么利用這個接口對一組 Student 對象進行排序的呢?我們在學習數組的時候,使用了一個類來給整型數組排序: java.util.Arrays 。我們使用 Arrays 的 sort 方法來給整型數組排序。翻翻 API 文檔就會發現, Arrays 里給出了 sort 方法很多重載形式,其中就包括 sort(Object[] obj) ,也就是說 Arryas 也能對對象數組進行排序,排序過程中比較兩個對象“大小”時使用的就是 Comparable 接口的 compareTo 方法。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class CompareTest {
 
 public static void main(String[] args) {
  Student stu1 = new Student(1, "Little");
  Student stu2 = new Student(2, "Cyntin");
  Student stu3 = new Student(3, "Tony");
  Student stu4 = new Student(4, "Gemini");
   
  Student[] stus = new Student[4];
  stus[0] = stu1;
  stus[1] = stu4;
  stus[2] = stu3;
  stus[3] = stu2;
  System.out.println(“Array: ” + Arrays.toString(stus));
  Arrays.sort(stus);
  System.out.println(“Sort: ” + Arrays.toString(stus));
 }
}

Student 數組里添加元素的順序并不是按學號 id 來添加的。調用了 Arrays.sort(stus) 之后,對 Student 數組進行排序,不管 sort 是使用哪種排序算法來實現的,比較兩個對象“大小”這個操作,它是肯定要做的。那么如何比較兩個對象的“大小”? Student 實現的 Comparable 接口就發揮作用了。 sort 方法會將待比較的那個對象強制類型轉換成 Comparable ,并調用 compareTo 方法,根據其返回值來判斷這兩個對象的“大小”。所以,在這個例子中排序后的原 Student 亂序數組就變成了按學號排序的 Student 數組。

但是我們注意到,排序算法和 Student 類綁定了, Student 只有一種排序算法。但現實社會不是這樣的,如果我們不想按學號排序怎么辦?假如,我們想按姓名來給學生排序怎么辦?我們只能修改 Student 類的 Comparable 接口的 compareTo 方法,改成按姓名排序。如果在同一個系統里有兩個操作,一個是按學號排序,另外一個是按姓名排序,這怎么辦?不可能在 Student 類體中寫兩個 compareTo 方法的實現。這么看來Comparable就有局限性了。為了彌補這個不足,JDK 還為我們提供了另外一個排序方式,也就是下面要說的比較器排序。

二、比較器排序:java.util.Comparator

上面我提到了,之所以提供比較器排序接口,是因為有時需要對同一對象進行多種不同方式的排序,這點自然排序 Comparable 不能實現。另外, Comparator 接口的一個好處是將比較排序算法和具體的實體類分離了。

翻翻 API 會發現, Arrays.sort 還有種重載形式:sort(T[] a, Comparator<? super T> c) ,這個方法參數的寫法用到了泛型,我們還沒講到。我們可以把它理解成這樣的形式: sort(Object[] a, Comparator c) ,這個方法的意思是按照比較器 c 給出的比較排序算法,對 Object 數組進行排序。Comparator 接口中定義了兩個方法: compare(Object o1, Object o2) equals 方法,由于 equals 方法所有對象都有的方法,因此當我們實現 Comparator 接口時,我們只需重寫 compare 方法,而不需重寫 equals 方法。Comparator 接口中對重寫 equals 方法的描述是:“注意,不重寫 Object.equals(Object) 方法總是安全的。然而,在某些情況下,重寫此方法可以允許程序確定兩個不同的 Comparator 是否強行實施了相同的排序,從而提高性能。”。我們只需知道第一句話就OK了,也就是說,可以不用去想應該怎么實現 equals 方法,因為即使我們不顯示實現 equals 方法,而是使用Object類的 equals 方法,代碼依然是安全的。

那么我們來寫個代碼,來用一用比較器排序。還是用 Student 類來做,只是沒有實現 Comparable 接口。由于比較器的實現類只用顯示實現一個方法,因此,我們可以不用專門寫一個類來實現它,當我們需要用到比較器時,可以寫個匿名內部類來實現 Comparator 。

下面是我們的按姓名排序的方法:

?
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 void sortByName () {
 Student stu1 = new Student(1, "Little");
 Student stu2 = new Student(2, "Cyntin");
 Student stu3 = new Student(3, "Tony");
 Student stu4 = new Student(4, "Gemini");
  
 Student[] stus = new Student[4];
 stus[0] = stu1;
 stus[1] = stu4;
 stus[2] = stu3;
 stus[3] = stu2;
 System.out.println("Array: " + Arrays.toString(stus));
 
 Arrays.sort(stus, new Comparator() {
 
  @Override
  public int compare(Object o1, Object o2) {
   if (o1 instanceof Student && o2 instanceof Student) {
    Student s1 = (Student) o1;
    Student s2 = (Student) o2;
    //return s1.getId() - s2.getId(); // 按Id排
    return s1.getName().compareTo(s2.getName()); // 按姓名排
   }
   return 0;
  }
   
 });
  
 System.out.println("Sorted: " + Arrays.toString(stus));
}

當我們需要對Student按學號排序時,只需修改我們的排序方法中實現Comparator的內部類中的代碼,而不用修改 Student 類。

注意: 當然,你也可以用 Student 類實現 Comparator 接口,這樣Student就是(is a)比較器了(Comparator)。當需要使用這種排序的時候,將 Student 看作 Comparator 來使用就可以了,可以將 Student 作為參數傳入 sort 方法,因為 Student is a Comparator 。但這樣的代碼不是個優秀的代碼,因為我們之所以使用比較器(Comparator),其中有個重要的原因就是,這樣可以把比較算法和具體類分離,降低類之間的耦合。

TreeSet對這兩種比較方式都提供了支持,分別對應著TreeSet的兩個構造方法:

     1、TreeSet():根據TreeSet中元素實現的 Comparable 接口的 compareTo 方法比較排序

   2、TreeSet(Comparator comparator):根據給定的 comparator 比較器,對 TreeSet 中的元素比較排序

當向 TreeSet 中添加元素時,TreeSet 就會對元素進行排序。至于是用自然排序還是用比較器排序,就看你的 TreeSet 構造是怎么寫的了。當然,添加第一個元素時不會進行任何比較, TreeSet 中都沒有元素,和誰比去啊?

下面,分別給出使用兩種排序比較方式的 TreeSet 測試代碼:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
 * 使用自然排序
 * Student必須實現Comparable接口,否則會拋出ClassCastException
 */
public void testSortedSet3() {
 Student stu1 = new Student(1, "Little");
 Student stu2 = new Student(2, "Cyntin");
 Student stu3 = new Student(3, "Tony");
 Student stu4 = new Student(4, "Gemini");
 
 SortedSet set = new TreeSet();
 set.add(stu1);
 set.add(stu3); // 若Student沒有實現Comparable接口,拋出ClassCastException
 set.add(stu4);
 set.add(stu2);
 set.add(stu4);
 set.add(new Student(12, "Little"));
 
 System.out.println(set);
}
?
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
34
/**
 * 使用比較器排序
 * Student可以只是個簡單的Java類,不用實現Comparable接口
 */
public void testSortedSet3() {
 Student stu1 = new Student(1, "Little");
 Student stu2 = new Student(2, "Cyntin");
 Student stu3 = new Student(3, "Tony");
 Student stu4 = new Student(4, "Gemini");
 
 SortedSet set = new TreeSet(new Comparator() {
 
  @Override
  public int compare(Object o1, Object o2) {
   if (o1 instanceof Student
     && o2 instanceof Student) {
    Student s1 = (Student) o1;
    Student s2 = (Student) o2;
    return s1.getName().compareTo(s2.getName());
   }
   return 0;
  }
   
 });
 
 set.add(stu1);
 set.add(stu3);
 set.add(stu4);
 set.add(stu2);
 set.add(stu4);
 set.add(new Student(12, "Little"));
 
 System.out.println(set);
}

另外,介紹個工具類,java.util.Collections。注意,這不是Collection接口。Collections很像Arrays類。Arrays提供了一系列用于對數組操作的靜態方法,查找排序等等。Collections也提供了一系列這樣的方法,只是它是用于處理集合的,雖然Collections類和Collection接口很像,但是不要被Collections的名字給欺騙了,它不是只能處理Collection接口以及子接口的實現類,同樣也可以處理Map接口的實現類。

總結

Java中自然排序和比較器排序的介紹就到這里了,文章介紹的還是相對詳細的,希望能對大家的學習或者工作帶來一定的幫助,如果有疑問大家可以留言交流。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国内永久第一免费福利视频 | 大学生初次破苞免费视频 | 青青青视频蜜桃一区二区 | 小女生RAPPER入口 | 美女的隐私视频免费看软件 | 国产图片综合区 | 青草久久网 | 欧美一级在线全免费 | 国产精品第2页 | 国产一区二区免费福利片 | 小舞同人18av黄漫网站 | 亚洲国产精品免费在线观看 | 厕所rxxx| 成人资源在线观看 | 精品国产自在天天线2019 | 欧美日韩在线观看精品 | 美女的让男人桶爽网站 | 全彩孕交漫画福利啪啪吧 | 日本不卡高清免费v日本 | a级片欧美 | 91久久精品视频 | 亚洲精品久久久打桩机 | 女人和拘做受全过程免费 | 精品亚洲午夜久久久久 | 欧美va在线| 欧美日韩亚洲成人 | 国产首页精品 | 欧美四级无删版影片 | 日本私人影院 | 别停好爽好深好大好舒服视频 | 牛牛在线观看 | avtt天堂网手机版亚洲 | 亚洲激情 欧美 | 精品久久久久亚洲 | 欧美人禽杂交在线视频 | 亚洲精品αv一区二区三区 亚洲精品91大神在线观看 | 国产在线观看精品香蕉v区 国产在线观看a | 青草视频网站在线观看 | 涩涩漫画免费 | 成人永久免费 | 亚洲成色 |