Java中的排序

Java中的排序

在技术面试中,排序相关的题目是必不可少的。那么,Java中的排序题目是怎样的呢?今天,咱们就来聊一聊这个话题。


说到排序,你脑子里可能会蹦出这些:冒泡排序、快速排序、选择排序、插入排序、希尔排序、基数排序、桶排序、归并排序等等。这些都是排序的方法论,是“数据结构与算法”要讨论的范畴。而今天我们的主题是Java中的排序,问题来了:

1. Java中如何实现数组的排序?
2. Java中如何实现List列表的排序?
3. Java中如何实现多个类型相同的对象的排序?
4. Java中如何实现多个类型相同的对象的比较?

我经常遇到一些面试者,当被问及诸如上述问题的时候,便大谈特谈各种排序算法。对于面试官而言,这种感觉就像“你问别人吃晚饭了没?他回答说我买了一辆豪车”,让人有一种你不懂我(你不是我要的人)的感觉。

其实,不管使用哪种算法进行排序,归根结底都要涉及一个根本问题:Java对象之间的顺序比较。提到比较,大家可能会想到equals()方法。但是,equals()方法只能进行对象之间的等同性比较,并不能进行对象之间的顺序比较(引用自《Effective Java》第2版第12条)。为此,Java中出现了Comparable接口。Jdk文档是这样描述它的:

This interface imposes a total ordering on the objects of each class that implements it. This ordering is referred to as the class's natural ordering, and the class's compareTo method is referred to as its natural comparison method. Lists (and arrays) of objects that implement this interface can be sorted automatically byCollections.sort(andArrays.sort). Objects that implement this interface can be used as keys in a sorted map or as elements in a sorted set, without the need to specify a comparator.
对于每一个实现该接口的类,其对象上都会被强行施加一种完全的排序。这种排序被称为该类的自然排序,其中的compareTo方法被称为该类的自然比较方法。实现了该接口的类的对象的List集合或Array数组可以通过Collections.sort方法或者Arrays.sort方法进行自动的排序。实现了该接口的类的对象可以被用作SortedMap类或者SortedSet类的键值,而不需要指定一个Comparator。

上面的文档告诉我们,可以使用Collections类或Arrays类的sort方法来对类对象的集合或数组进行排序,前提是对象所属的类需要实现Comparable接口。再来看看Jdk文档对这两个sort方法的描述:

对于Collections.sort(List<T> list)方法,Jdk文档是这样说的:

Sorts the specified list into ascending order, according to the natural ordering of its elements. All elements in the list must implement the Comparable interface. Furthermore, all elements in the list must be mutually comparable (that is, e1.compareTo(e2) must not throw a ClassCastException for any elements e1 and e2 in the list).
根据自然顺序对列表中的元素进行升序排序。所有的元素都必须实现Comparable接口。而且,列表中所有元素之间都必须是可比较的。即对于列表中的任意两个元素e1和e2,e1.compareTo(e2)不能抛出类型转换异常。

对于Arrays.sort(Object[] a)方法,Jdk文档是这样说的:

Sorts the specified array of objects into ascending order, according to the natural ordering of its elements. All elements in the array must implement theComparableinterface. Furthermore, all elements in the array must be mutually comparable(that is, e1.compareTo(e2) must not throw a ClassCastException for any elements e1 and e2 in the array).
根据自然顺序对数组中的元素进行升序排序。所有的元素都必须实现Comparable接口。而且,数组中所有元素之间都必须是可比较的。即对于列表中的任意两个元素e1和e2,e1.compareTo(e2)不能抛出类型转换异常。

除了上述的两个方法,在介绍Comparable接口时,还提到了SortdMap和SortedSet。

对于SortedMap,Jdk文档是这样说的:

A Map that further provides a total ordering on its keys. The map is ordered according to the natural ordering of its keys, or by aComparatortypically provided at sorted map creation time. This order is reflected when iterating over the sorted map's collection views (returned by theentrySet,keySetandvaluesmethods).
SortedMap是一种进一步提供元素排序功能的Map。其中的元素被按照其键的自然顺序进行排序,或者是按照创建此SortedMap时提供的Comparator进行排序。在对SortedMap的集合视图进行遍历时,将反映此顺序(比如entrySet,keySetvalues等方法的返回)。

对于SortedSet,Jdk文档是这样说的:

A Set that further provides a total ordering on its elements. The elements are ordered using their natural ordering, or by aComparatortypically provided at sorted set creation time. The set's iterator will traverse the set in ascending element order.
SortedSet是一种进一步提供元素排序功能的Set。这些元素被按照它们的自然顺序进行排序,或者是按照创建此SortedSet时提供的Comparator进行排序。SortedSet的迭代器将按照升序遍历其中的元素。

上面这些文档,处处都有Comparator的影子。如果一个类实现了Comparable接口,那么它“天生”就是可以借助Collections、Arrays、SortedMap、SortedSet等类来进行排序。

但是,如果一个类没有实现Comparable接口,却也想利用Collections、Arrays、SortedMap、SortedSet等来进行排序,就可以通过指定一个自定义的Comparator来实现。

至此,我们来看之前的面试题目:

  1. Java中通过使用Arrays.sort(Object[] a)方法来对数组进行排序,此时数组中元素对应的类需要实现Comparable接口。如果对应的类没有实现Comparable接口,可以先实现一个Comparator,然后使用Arrays.sort(T[] a,Comparator<? super T> c)方法进行排序。
  2. Java中通过使用Collections.sort(List<T> list)方法来对列表进行排序,此时List中元素对应的类需要实现Comparable接口。如果对应的类没有实现Comparable接口,可以先实现一个Comparator,然后使用Collections.sort(List<T> list,Comparator<? super T> c)方法进行排序。
  3. Java中可以使用Collections.sort()对列表进行排序,可以使用Arrays.sort()对数组进行排序,还可以通过把多个元素放到SortedSet或者SortedMap中进行排序。使用这个类进行排序时需要注意元素对应的类是否实现了Comparable接口,如果没有,需要在排序前指定一个Comparator。
  4. 对象的比较分为等同性比较和顺序性比较,等同性比较使用equals方法,顺序性比较使用Comparable接口或者Comparator接口。

下次面试的时候,你能答对了吗!@E-臻


一个介绍Java学习路线的Live:(已有2800+人收听,5200+人支持)

学习Java,我建议这样做​www.zhihu.comwww.zhihu.com图标

一个介绍入门云计算的Live:

入门云计算:你该了解的那些事儿www.zhihu.com图标

编辑于 2019-02-01

文章被以下专栏收录