溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Java中Sorting知識(shí)點(diǎn)有哪些

發(fā)布時(shí)間:2021-11-15 16:08:22 來源:億速云 閱讀:102 作者:iii 欄目:大數(shù)據(jù)

這篇文章主要講解了“Java中Sorting知識(shí)點(diǎn)有哪些”,文中的講解內(nèi)容簡(jiǎn)單清晰,易于學(xué)習(xí)與理解,下面請(qǐng)大家跟著小編的思路慢慢深入,一起來研究和學(xué)習(xí)“Java中Sorting知識(shí)點(diǎn)有哪些”吧!

兩個(gè)接口

Comparable

先上代碼:

package java.lang;

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

可以看出這個(gè)接口只有一個(gè)方法,這個(gè)方法只有一個(gè)參數(shù),實(shí)現(xiàn)了這個(gè)接口的類就可以和同類進(jìn)行比較了。這個(gè)方法所實(shí)現(xiàn)的,就是比較法則,也是說,它表示如何對(duì)兩個(gè)對(duì)象進(jìn)行比較。 它返回的是一個(gè)整數(shù)int:

  • 返回正數(shù),代表當(dāng)前對(duì)象大于被比較的對(duì)象;

  • 返回0,代表當(dāng)前對(duì)象等于于被比較的對(duì)象;

  • 返回負(fù)數(shù),代表當(dāng)前對(duì)象小于被比較的對(duì)象。

實(shí)現(xiàn)了該接口后,我們就可以使用Arrays.sort()和Collections.sort()來進(jìn)行排序了。 不然對(duì)象沒有比較法則,程序肯定是不知道如何進(jìn)行比較排序的。 像我們常用的類String、Integer、Double、Date等,JDK都幫我們實(shí)現(xiàn)了Comparable接口,我們可以直接對(duì)這類對(duì)象進(jìn)行比較排序。 舉個(gè)例子,Date Comparable的實(shí)現(xiàn):

public int compareTo(Date anotherDate) {
    long thisTime = getMillisOf(this);
    long anotherTime = getMillisOf(anotherDate);
    return (thisTime<anotherTime ? -1 : (thisTime==anotherTime ? 0 : 1));
}

需要注意的是,當(dāng)我們自己去實(shí)現(xiàn)Comparable接口時(shí),一定要注意與**equals()**方法保持一致。當(dāng)兩個(gè)對(duì)象是equals的,compare的結(jié)果應(yīng)該是相等的。

Comparator

還是先看代碼,看看接口定義吧:

package java.util;

@FunctionalInterface
public interface Comparator<T> {   
    int compare(T o1, T o2);    
}

它是一個(gè)函數(shù)式接口,它的compare方法有兩個(gè)參數(shù),代表進(jìn)行比較的兩個(gè)對(duì)象。這個(gè)接口代表了可以作為某種對(duì)象比較的一種法則,或叫一種策略。 它的返回值正負(fù)代表意義與Comparable接口的方法一樣。 它的使用通常會(huì)有三種方式:

  1. 實(shí)現(xiàn)類

  2. 匿名類

  3. Lambda表達(dá)式

在Java8之后,我們一般用Lambda比較多,也比較靈活優(yōu)雅。

兩個(gè)接口的比較

兩個(gè)接口功能都是用于比較排序,但其實(shí)有很大的區(qū)別。

  1. 兩者方法參數(shù)不同,Comparable只有一個(gè)參數(shù),表示被比較的對(duì)象,因?yàn)樗姆椒ㄊ俏挥谛枰容^的類里的,所以只要一個(gè)參數(shù)就可以了;而Comparator的比較方法則有兩個(gè)參數(shù),分別表示比較對(duì)象和被比較對(duì)象。

  2. Comparable與對(duì)象綁定,位于對(duì)象內(nèi),我們可以稱之為內(nèi)比較器;而Comparator是獨(dú)立于需要比較的類的,我們可以稱為外比較器

  3. 當(dāng)類實(shí)現(xiàn)了Comparable方法后,比較法則就確定了,我們稱之為自然比較方法,我們無法給它實(shí)現(xiàn)多種比較方法;而因?yàn)镃omparator獨(dú)立于外,我們可以為同一個(gè)類提供多種Comparator的實(shí)現(xiàn),這樣來提供多種比較方法/策略,如升序倒序,因此我們也可以將Comparator看成是一種策略模式。

相對(duì)于Comparable,Comparator有一定的靈活性,假如一個(gè)類并沒有實(shí)現(xiàn)Comparable接口,并且這個(gè)類是無法修改的,我們就要通過提供Comparator來進(jìn)行比較排序。 Comparator這種模式實(shí)現(xiàn)了數(shù)據(jù)與算法的解耦合,對(duì)于維護(hù)也是很方便的。


工具類

十分友好的是,JDK為我們提供了工具類,它們的靜態(tài)方法可以幫助我們直接對(duì)數(shù)組和List進(jìn)行排序。

數(shù)組排序Arrays

Arrays的sort方法可以對(duì)已經(jīng)實(shí)現(xiàn)了Comparable接口的進(jìn)行排序,同時(shí)還可指定排序的范圍。

//Arrays.sort對(duì)String進(jìn)行排序
String[] strings = {"de", "dc", "aA", "As", "k", "b"};
Arrays.sort(strings);
assertTrue(Arrays.equals(strings,
        new String[]{"As", "aA", "b", "dc", "de", "k"}));

指定范圍排序,需要注意的是,index是從0開始算的,包含fromIndex,不包含toIndex:

//Arrays.sort指定范圍排序
strings = new String[]{"z", "a", "d", "b"};
Arrays.sort(strings, 0, 3);
assertTrue(Arrays.equals(strings,
        new String[]{"a", "d", "z", "b"}));

對(duì)于基本類型,一樣可以進(jìn)行排序,并不需要使用封裝類:

//Arrays.sort對(duì)基本類型排序
int[] nums = {3, 1, 20, 2, 38, 2, 94};
Arrays.sort(nums);
assertTrue(Arrays.equals(nums,
        new int[]{1, 2, 2, 3, 20, 38, 94}));

還能多線程進(jìn)行排序,其實(shí)是拆分成多個(gè)子數(shù)組再進(jìn)行排序,最終再合并結(jié)果。

//Arrays.parallelSort多線程排序
nums = new int[]{3, 1, 20, 2, 38, 2, 94};
Arrays.parallelSort(nums);
assertTrue(Arrays.equals(nums,
        new int[]{1, 2, 2, 3, 20, 38, 94}));

對(duì)于沒有實(shí)現(xiàn)Comparable的類也可以使用,但需要提供Comparator來指定比較策略。 本文的沒有實(shí)現(xiàn)Comparable接口的類Person如下:

import lombok.AllArgsConstructor;
import lombok.Data;

@Data
@AllArgsConstructor
public class Person {
    private String name;
    private int age;
}

排序:

//Arrays.sort提供Comparator進(jìn)行排序
Person[] persons = new Person[]{
        new Person("Larry", 18),
        new Person("David", 30),
        new Person("James", 20),
        new Person("Harry", 18)};
Arrays.sort(persons, Comparator.comparingInt(Person::getAge));
assertTrue(Arrays.equals(persons, new Person[]{
        new Person("Larry", 18),
        new Person("Harry", 18),
        new Person("James", 20),
        new Person("David", 30)}));

List排序Collections

JDK的Collections工具類提供了排序方法,可以方便使用。 對(duì)于實(shí)現(xiàn)Comparable的類進(jìn)行排序:

//Collections.sort對(duì)于實(shí)現(xiàn)Comparable的類進(jìn)行排序
List<String> names = asList("Larry", "Harry", "James", "David");
Collections.sort(names);
assertEquals(names, asList("David", "Harry", "James", "Larry"));

提供Comparator進(jìn)行排序:

//Collections.sort提供Comparator進(jìn)行排序
List<Person> persons2 = asList(
        new Person("Larry", 18),
        new Person("David", 30),
        new Person("James", 20),
        new Person("Harry", 18));
Collections.sort(persons2, Comparator.comparingInt(Person::getAge));
assertEquals(persons2, asList(
        new Person("Larry", 18),
        new Person("Harry", 18),
        new Person("James", 20),
        new Person("David", 30)));

反序:只是把List反過來,并不代表一定是按照大小順序的:

//Collections.reverse反序
names = asList("Larry", "Harry", "James", "David");
Collections.reverse(names);
assertEquals(names, asList("David", "James", "Harry", "Larry"));

成員方法

List排序

List接口有sort(Comparator<? super E> c)方法,可以實(shí)現(xiàn)對(duì)自身的排序,會(huì)影響自身的順序

//List.sort排序
names = asList("Larry", "Harry", "James", "David");
names.sort(Comparator.naturalOrder());
assertEquals(names, asList("David", "Harry", "James", "Larry"));

Stream排序

Stream提供了sorted()和sorted(Comparator<? super T> comparator)進(jìn)行排序,會(huì)返回一個(gè)新的Stream。

//Stream.sorted排序
names = asList("Larry", "Harry", "James", "David");
List<String> result = names.stream()
        .sorted()
        .collect(Collectors.toList());
assertEquals(result, asList("David", "Harry", "James", "Larry"));

//Stream.sorted提供Comparator排序
names = asList("Larry", "Harry", "James", "David");
result = names.stream()
        .sorted(Comparator.naturalOrder())
        .collect(Collectors.toList());
assertEquals(result, asList("David", "Harry", "James", "Larry"));

方便對(duì)象排序的Comparator

單字段排序

對(duì)類的單字段進(jìn)行排序很簡(jiǎn)單,只要提供形如:

  • Comparator.comparing(類名::屬性getter)

的Comparator就行了。如果需要倒序,就需要:

  • Comparator.comparing(類名::屬性getter).reversed()

  • Comparator.comparing(類名::屬性getter, Comparator.reverseOrder())

具體代碼使用(為了不破壞List的原有順序,我們都使用Stream來操作):

//單字段排序-升序
List<Person> personList = asList(
        new Person("Larry", 18),
        new Person("David", 30),
        new Person("David", 3),
        new Person("James", 20),
        new Person("Harry", 18));
List<Person> personResult = personList.stream()
        .sorted(Comparator.comparing(Person::getName))
        .collect(Collectors.toList());
assertEquals(personResult, asList(
        new Person("David", 30),
        new Person("David", 3),
        new Person("Harry", 18),
        new Person("James", 20),
        new Person("Larry", 18)));

//單字段排序-倒序1
personResult = personList.stream()
        .sorted(Comparator.comparing(Person::getName).reversed())
        .collect(Collectors.toList());
assertEquals(personResult, asList(
        new Person("Larry", 18),
        new Person("James", 20),
        new Person("Harry", 18),
        new Person("David", 30),
        new Person("David", 3)));
//單字段排序-倒序2
personResult = personList.stream()
        .sorted(Comparator.comparing(Person::getName, Comparator.reverseOrder()))
        .collect(Collectors.toList());
assertEquals(personResult, asList(
        new Person("Larry", 18),
        new Person("James", 20),
        new Person("Harry", 18),
        new Person("David", 30),
        new Person("David", 3)));

多字段排序

多字段其實(shí)也很方便,只需要用thenComparing進(jìn)行連接就可以: Comparator.comparing(類名::屬性一getter).thenComparing(類名::屬性二getter) 具體代碼使用例子如下:

//多字段排序-1升2升
personResult = personList.stream()
        .sorted(Comparator.comparing(Person::getName)
                .thenComparing(Person::getAge))
        .collect(Collectors.toList());
assertEquals(personResult, asList(
        new Person("David", 3),
        new Person("David", 30),
        new Person("Harry", 18),
        new Person("James", 20),
        new Person("Larry", 18)));

//多字段排序-1升2倒
personResult = personList.stream()
        .sorted(Comparator.comparing(Person::getName)
                .thenComparing(Person::getAge, Comparator.reverseOrder()))
        .collect(Collectors.toList());
assertEquals(personResult, asList(
        new Person("David", 30),
        new Person("David", 3),
        new Person("Harry", 18),
        new Person("James", 20),
        new Person("Larry", 18)));

//多字段排序-1倒2升
personResult = personList.stream()
        .sorted(Comparator.comparing(Person::getName, Comparator.reverseOrder())
                .thenComparing(Person::getAge))
        .collect(Collectors.toList());
assertEquals(personResult, asList(
        new Person("Larry", 18),
        new Person("James", 20),
        new Person("Harry", 18),
        new Person("David", 3),
        new Person("David", 30)));

//多字段排序-1倒2倒
personResult = personList.stream()
        .sorted(Comparator.comparing(Person::getName, Comparator.reverseOrder())
                .thenComparing(Person::getAge, Comparator.reverseOrder()))
        .collect(Collectors.toList());
assertEquals(personResult, asList(
        new Person("Larry", 18),
        new Person("James", 20),
        new Person("Harry", 18),
        new Person("David", 30),
        new Person("David", 3)));

感謝各位的閱讀,以上就是“Java中Sorting知識(shí)點(diǎn)有哪些”的內(nèi)容了,經(jīng)過本文的學(xué)習(xí)后,相信大家對(duì)Java中Sorting知識(shí)點(diǎn)有哪些這一問題有了更深刻的體會(huì),具體使用情況還需要大家實(shí)踐驗(yàn)證。這里是億速云,小編將為大家推送更多相關(guān)知識(shí)點(diǎn)的文章,歡迎關(guān)注!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI