报告错误
如果你发现该网页中存在错误/显示异常,可以从以下两种方式向我们报告错误,我们会尽快修复:
- 使用 CS Club 网站错误 为主题,附上错误截图或描述及网址后发送邮件到 286988023@qq.com
- 在我们的网站代码仓库中创建一个 issue 并在 issue 中描述问题 点击链接前往Github仓库
你使用哪种语言?我们会根据你选择的语言显示对应的代码示例
注意,这个页面并不是描述排序算法的页面。这个页面描述的是各个语言具体如何实现对数组的排序。如果你想看排序算法相关的内容,点击这里
前置条件
在 Java 中,一般我们只会对 ArrayList
中的对象进行排序操作。在对数组排序时,我们会使用 ArrayList.sort
方法。这个方法不会有返回值,会直接在原来的 ArrayList 上进行修改。
在 Java 中对语言自带的类型进行排序
如果我们要对数组进行排序,仅仅调用 ArrayList.sort()
是不够的,我们还要告诉 Java 如何对 List 中的对象进行排序 - 这里我们就要引入 Comparator
的概念了。Comparator 对象是专门用来比较两个对象大小的。ArrayList
进行排序的时候会调用传入的 Comparator
对象进行排序。
import java.util.*;
public class compareExample {
public static void main(String[] args) {
ArrayList<Integer> arr = new ArrayList<>();
arr.add(1);
arr.add(8);
arr.add(3);
arr.add(5);
arr.sort(Comparator.naturalOrder());
System.out.println(arr); // Output: [1, 3, 5, 8]
arr.sort(Comparator.reverseOrder());
System.out.println(arr); // Output: [8, 5, 3, 1]
}
}
在上面这段代码中,我们向 arr 传入了 Comparator.naturalOrder()
这样一个对象。如同它的名字所描述的,这个比较器的作用就是将Array中的内容按照“自然顺序”排列 - 也就是从小到大的顺序。类似naturalOrder
,java.util.Comparator
中还有其他的比较器,例如 reverseOrder
(将List中的元素从大到小的排序)等。
如果你想排序的 ArrayList 中存放的元素是 Java 已给出的数据类型,那么对它们进行排序就只需要上面这一步就好了。然而,如果你想对自己声明的类型进行排序,我们还需要做一些额外的工作……
在 Java 中对自己定义的类进行排序
如果你想对自己定义的类进行排序,那么有以下两种方法实现:
- 在自己的类中实现 Java 定义的
Comparable
接口 - 自己为自己的类实现一个
Comparator
类型,并将这个 Comparator 传到arr.sort()
中。
下面,假设我们要对这样一个 Java 类进行排序:
class Person{
public int age;
public String name;
public Person(int age, String name){
this.age = age;
this.name = name;
}
public String toString(){
return "( age: " + this.age + ", name: " + this.name + " )";
}
}
实现 Comparable 接口 (推荐)
通过实现 Comparable 接口,Java会识别到这个类是“可比较的”。在调用 ArrayList.sort()
的时候,Comparator
会调用你的类中的 compareTo
方法来判断两个对象之间的大小关系。
public int compareTo(object other){
/*
If this object is bigger than the "other" given in the parameter, return a positive integer.
if this object is smaller than the "other" given in parameter, return a negative integer.
Otherwise, return 0.
*/
}
具体的写法如下:
class Person implements Comparable<Person>{
public int age;
public String name;
public Person(int age, String name){
this.age = age;
this.name = name;
}
public int compareTo(Person other){
if (this.equals(other)){ return 0; }
if (this.age != other.age){ return this.age - other.age; }
else{ return this.name.compareTo(other.name); }
}
public boolean equals(Person other){
return this.age == other.age && this.name.equals(other.name);
}
public String toString(){
return "( age: " + this.age + ", name: " + this.name + " )";
}
}
如果你在自己的Java类上实现了Comparable
接口,那么在数组排序时所有 java.util.Comparator
中的比较器都可以直接传入给 ArrayList
。
import java.util.*;
public class compareTest{
public static void main(String[] args) {
ArrayList<Person> arr = new ArrayList<>();
arr.add(new Person(17, "Mark"));
arr.add(new Person(14, "Test"));
arr.add(new Person(18, "wyn"));
arr.sort(Comparator.naturalOrder());
System.out.println(arr);
}
}
运行结果:
[( age: 14, name: Test ), ( age: 17, name: Mark ), ( age: 18, name: wyn )]
实现 Comparator 类型 (不推荐)
除了直接实现Comparable
接口以外,我们还可以直接定义一个可以比较两个自己类型对象的比较器(Comparator)来达到对存储这个类型对象的数组进行排序的目的。这种情况下,我们要新建一个比较器类型来实现 Comparator 抽象类。Comparator 抽象类只有一个函数 - compare
。所以如果我们想实现一个效果和上文的方案相同的比较器,我们可以这样写:
class PersonComparator implements Comparator<Person>{
public int compare(Person o1, Person o2){
if (o1 == o2){ return 0; }
if (o1.age != o2.age) { return o1.age - o2.age; }
else{ return o1.name.compareTo(o2.name); }
}
}
这种情况下,我们要对Person
类进行排序就需要将自己定义的比较器传入ArrayList.sort()
中来进行排序。
import java.util.*;
public class compareTest{
public static void main(String[] args) {
ArrayList<Person> arr = new ArrayList<>();
arr.add(new Person(17, "Mark"));
arr.add(new Person(14, "Test"));
arr.add(new Person(18, "wyn"));
arr.sort(new PersonComparator());
System.out.println(arr);
}
}
输出结果如下:
[( age: 14, name: Test ), ( age: 17, name: Mark ), ( age: 18, name: wyn )]
Python 对元组和内置数据类型的排序
对于 Python 来说,数组的排序会变得简单很多:在Python中,你可以随意创建含有多个不同类型元素的数据对象 - Tuple (元组)。Python在比较元组大小时会先比较第0位大小,如果大小相同比较第1位……依此类推,直到找到最后一位或者大小不同的一位为止。
例子:
arr = [(1, "test"), (10, "ebc"), (10, "abc"), (3, "wasd")]
arr.sort()
结果:
[(1, 'test'), (3, 'wasd'), (10, 'abc'), (10, 'ebc')]
Python 对自己写的类进行排序
如果你试着直接对一个装有自己写的类的对象进行排序,Python会丢出这样的报错:
Traceback (most recent call last): File "d:\Python_Files\prime\compareV1.py", line 8, in <module> ... TypeError: '>' not supported between instances of 'Person' and 'Person'
这是因为我们没有规定如何比较两个 Person 对象之间的大小关系。和Java类似,在Python中也有两种方法对自己写的类进行排序。
- 为自己的类实现
__gt__
,__lt__
,__eq__
等方法使类的对象之间支持比较大小 - 在 arr.sort 时手动写入一个
Comparator
函数用来比较两个对象的大小关系,以 keyword arguement 形式将这个函数传入sort
方法。
假设我们要对装有这样一个类的对象的数组进行排序……
class Person:
def __init__(self, age, name):
self.age = age
self.name = name
def __repr__(self):
return "(age: {}, name: {})".format(self.age, self.name)
实现Python内置的,用于比较大小的方法
这种方法和 Java 中为自己的类实现 Comparable 接口非常相似,唯一的不同是没有显式的表明自己实现了Comparable接口/功能。 Python 中一共有五个内置的,用于比较对象之间大小关系的函数:__gt__
, __lt__
, __eq__
, __ge__
, __le__
,分别对应大于,小于,相等,大于等于 和 小于等于 的判断。这里我们只需要实现前三个函数就好了。这三个函数返回一个布尔值,表明自己和传入的对象之间的关系是否是函数名所描述的关系。
class Person:
def __init__(self, age, name):
self.age = age
self.name =
def __repr__(self):
return "(age: {}, name: {})".format(self.age, self.name)
def __lt__(self, otherPerson):
if self.age != otherPerson.age: return self.age < otherPerson.age
else: return self.name < otherPerson.name
def __gt__(self, otherPerson):
if self.age != otherPerson.age: return self.age > otherPerson.age
else: return self.name > otherPerson.name
def __eq__(self, otherPerson):
return self.age == otherPerson.age and self.name == otherPerson.name
效果:
arr = [Person(23, "test1"), Person(17, "John"), Person(19, "Penny"), Person(21, "Mary"), Person(23, "test2")]
arr.sort()
print(arr)
[(age: 17, name: John), (age: 19, name: Penny), (age: 21, name: Mary), (age: 23, name: test1), (age: 23, name: test2)]
向 List.sort()
传入比较方法
在我们调用sort方法时,有一个隐藏的 keyword arguement 是 key = function
。这里的 function
是一个函数。如果这个参数被传递进了 sort 方法,那么在sort在比较大小时,Python会先将list中的对象传入 function
,然后根据函数返回值进行排序。例如我们只想通过 Person 的 age 属性对 Person 对象进行排序,那么我们可以用这样一个 lambda 函数作为 key 传入 sort 方法。(注意:这时候即使 Person 没有实现 __lt__
, __gt__
, __eq__
方法也可以进行排序。)
arr = [Person(23, "test1"), Person(17, "John"), Person(19, "Penny"), Person(21, "Mary"), Person(23, "test2")]
arr.sort(key= lambda personObj: personObj.age)
print(arr)
当然,如果 key 所对应的函数逻辑较为复杂,也可以在外面定义完以后再传入key参数。
def convertPerson(personObj):
# convert a person object into a comparable object
return str(personObj.age) + personObj.name
arr = [Person(23, "test1"), Person(17, "John"), Person(19, "Penny"), Person(21, "Mary"), Person(23, "test2")]
arr.sort(key = convertPerson)
print(arr)
练习
-
如何让二维坐标按照x轴优先的顺序从小到大排序? -
LeetCode Problem 1641. Count Sorted Vowel Strings -
LeetCode Problem 324. Wiggle Sort II -
LeetCode Problem 922. Sort Array By Parity II -
LeetCode Problem 82. Remove Duplicates from Sorted List II -
USACO 2019 Jan Silver P3 -
USACO 2018 Jan Silver P2 -
USACO 2019 Jan Silver P1