Java排序方法总结

  • Post author:
  • Post category:java





前提

在处理与线性数据结构有关的问题的时候,经常需要用到排序。我们知道,对于基础类型的数组,我们可以用

Arrays.sort()

这个函数来进行排序,方便又快捷。

但是对于泛型列表类型

List

,我们就束手无策了。

这篇博文主要总结对各类线性数据结构的排序方法。




对基础类型和封装类型的数组进行排序

所谓基础类型,即

int



double



boolean



char

等;所谓封装类型,即

Integer



Double



String



Boolean

等。当我们需要对它们构成的数组进行排序时,可以调用

Arrays.sort()

函数来做,它内部使用归并排序,时间消耗上比快速排序要稳定。

举一个例子:

	int[] array = new int[]{1, 9, 3, 7, 4, 6, 8, 2, 5};
    Arrays.sort(array);

排序结果:

1 2 3 4 5 6 7 8 9



默认排序规则

针对每种数据类型,

Arrays.sort()

函数都有默认的排序规则,总体上依照数值上小的在前面,大的在后面这样的规则。


int



float



double



Integer



String



Boolean

这类的就不用多说了,按数值大小排;


char

按照字符

ASCII

码的大小来排;


String

从每个字符串的第一个字符开始比较

ASCII

码,小的在前,大的在后;


Boolean

按照

false < true

的规则进行排序


......




对泛型列表List<T>进行排序

泛型列表

List<T>

是除数组外,我们最经常用到的线性数据结构。与数组相比,它的优点在于

可变长。

比如我们可以定义以下的List:

	List<Integer> nums = new ArrayList<>();
	class User {
		int id;
		int age;
		String name;
	}
	List<User> users = new ArrayList<>();


对List进行排序,我们可以调用Collections.sort()函数,他有两个重载:

	sort(List<T> list)
	sort(List<T> list, Comparator<? super T> c)

对于上述

nums

这种只存单值的列表来说,用第一个重载就可以,默认的排序规则就可以满足要求。

对于上述

users

这种存放自定义类型的列表来说,我们所需的排序规则可能会根据需求发生变化,比如,我需要根据年龄

age

排序,或者我需要根据姓名

name

排序,那么此时就需要上述的第二种重载,由此我们就需要引入比较器

Comparator




比较器Comparator


Comparator

是一个类,需要自定义一个Comparator时需要继承它然后实现

compare

方法。

该方法的返回值为

int

型,它关注的是两个被比较的对象何时

算作

前者大于后者(返回1)、何时

算作

相等(返回0)、以及何时

算作

后者大于前者(返回-1)。

举例说明:

    private class UserAgeComparator implements Comparator<User> {
        @Override
        public int compare(User a, User b) {
            return a.age < b.age ? -1 : a.age == b.age ? 0 : 1;
        }
    }

这里用了两个嵌套三元运算符

?:

来比较用户

a



b

的年龄

age

,当

a.age > b.age

时返回

1

,当

a.age < b.age

时返回

-1

,否则返回

0




执行排序

执行排序的时候,只需要调用

Collections.sort()

函数,传入待排序的列表和自定义的比较器的

实例

	Collections.sort(users, new UserAgeComparator());


亲测速度很快,再也不用背快排算法了,哈哈。




后记



1. 深究一下Collections.sort()的实现:

    public static <T> void sort(List<T> list, Comparator<? super T> c) {
        list.sort(c);
    }

可以看到,它调用了

List



sort

函数,再点进去:

    default void sort(Comparator<? super E> c) {
        Object[] a = this.toArray();
        Arrays.sort(a, (Comparator) c);
        ListIterator<E> i = this.listIterator();
        for (Object e : a) {
            i.next();
            i.set((E) e);
        }
    }


可以看这个函数的前两行,它实际就是把

list



toArray

函数转换成数组,然后调用的是

Arrays.sort()

需要传入比较器的那个重载。



2. 比较器的lambda表达式写法

最近在做题看别人的代码时,发现Comparator可以用lambda表达式简写,

尤其是比较器我们经常也是只用一次,没有必要单写一个内部类出来,代码会简洁很多。

同样针对上述的

User类

,以下是比较器的简写形式:

(a, b) -> (a.age < b.age ? -1 : a.age == b.age ? 0 : 1);


比较器的返回值不一定要是

-1, 0, 1

,只要能区分两个数之间的大小就可以了,所以我们可以简写做:

(a, b) -> (a.age - b.age);


用法如下:

//假设points是一个二维数组,每行的0,1两位存一个点的横纵坐标。对每个点按横坐标排序
Arrays.sort(points, (a, b) -> (a[0] - b[0]));
//假设users是一个List<User>。对每个用户按年龄排序
Collections.sort(users, (a, b) -> (a.age - b.age));



版权声明:本文为Mr_Megamind原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。