Java中如何使用排序详解

本文介绍了Java中Arrays.sort()和Collections.sort()的使用,详细解析了这两种方法在基本类型和对象类型排序上的实现原理。对于基本类型,Arrays.sort()使用快速排序和优化后的归并排序,而Collections.sort()则采用归并排序。在对象类型排序时,通过Comparable接口和Comparator接口实现排序规则。总结比较了两者在对象排序中的区别和适用场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

1.问题的提出

  在前面的文章中已经总结了数据结构中的八大基本排序方法,因为平时主要使用Java语言进行开发,因此想到在Java中使用的是哪一种排序方法呢?快速排序还是归并排序,或是其它》又该怎么使用它们呢?

2.基本类型的排序

  一提到Java中的排序方法,自然想到的是sort()方法。在JDK中,拥有sort()方法的类主要有java.util.Arrays和java.util.Collections(注意和Collection接口的区别)。
  jdk中的sort

Arrays.sort()

  Java中的Arrays.sort()主要采用了两种排序方法,分别是快速排序和优化之后的归并排序。其中快速排序主要是对于基本数据类型(int,short,long等),而归并排序主要用于对象类型。
  为什么要这样区分开呢?这主要是考虑到不同的排序需求。我们知道,排序方法分为稳定不稳定,我们知道快速排序是不稳定的,归并排序是稳定的。
  对于基本数据类型如int,两个int型的4,4进行排序,谁前谁后都没有特别的意义,所以使用快速排序。而对于对象类型,一个对象可能有多个属性,我们很可能只是根据它们其中的一个关键属性进行排序,那么,最好保持相等对象的非关键属性的顺序与排序前一致,所以这种情况使用归并排序。
  另外一个原因是由于归并排序相对而言比较次数比快速排序少,移动(对象引用的移动)次数比快速排序多,而对于对象来说,比较一般比移动耗时,因此选择归并排序。
  归并排序的时间复杂度是O(nlogn), 快速排序的平均时间复杂度也是O(nlogn),但是归并排序的需要额外的n个引用的空间。

Collections.sort()

  Java中的Collections.sort()采用的是归并排序,是稳定的排序方法,当待排序咧接近有序的时候,效率更高。
  问题:既然Arrays和Collections都可以实现排序,那么它们有什么区别,在什么情况下该使用哪一个呢?
  一般的,在待排序序列是基本数据类型时(对象类型稍后讲述),我们通常使用Arrays对数组进行排序,使用Collections对集合框架容器进行排序,如List。
  比如:

int[] intArray = new int[] {4,1,3,-23};
Arrays.sort(intArray);
//输出结果为:-23,1,3,4
String[] strArray = new String[] {"z","a","C"};
Arrays.sort(strArray);
//输出结果为:C,a,z
Arrays.sort(strArray,String.CASE_INSENSITIVE_ORDER);
//输出结果为:a,C,z
//Arrays.sort方法只能按照升序排列,其本身没有reverse这样的方法,但是可以通过设置比较器进行降序排列
//此处可以借助Collections.reverseOrder()这个比较器实现降序排列
Arrays.sort(strArray,Collections.reverseOrder());
//输出结果为:z,a,C
Arrays.sort(strArray,String.CASE_INSENSITIVE_ORDER);
Collections.reverse(Arrays.asList(strArray));
//输出结果为:z,C,a

  当然,我们也可以指定对数组的某一段进行排序:Arrays.sort(strArray,0,2);这样我们只对前三个元素进行排序,不会影响到后面部分的顺序。
  Collections.sort()当然也可以实现对基本数据类型序列的排序,只需要将待排序序列放到一个List中就可以了。

List<Integer> intList = new ArrayList<Integer>();
intList.add(3);
intList.add(23);
intList.add(-1);
Collections.sort(intList);

  由于此处是对基本数据类型进行排序,而且Collections有自己的降序方法,所以不需要比较器。只有在下面讲述的对对象类型进行排序的时候才用到比较器。

3.对象类型的排序

  问题:上面讲的都是对基本数据类型的排序,那么当待排序序列为对象的时候该怎么办呢?下面我们就来看看Arrays.sort()和Collections.sort()分别是怎么运用才能对对象类型进行排序。

Comparable接口&Comparator接口

  Comparable接口之中只有一个方法compareTo(),如果一个对象要要实现可排序,在实现了Comparable接口后,必须在对象内部重写compareTo方法(即定义自己需要的排序规则),因此我们称Comparable是在对象内部需要实现的接口;与此对应,Comparator接口是在对象外实现的接口,不需要在对象内部定义排序规则。这主要是方便对没有实现Comparable接口的对象进行比较和排序。
  Comparable接口使用示例:

public class User implements Comparable<Object> {
private String id;
private int age;
public User(String id, int age) {
this.id = id;
this.age = age;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
//定义自己需要的排序规则
//规则为:按照年龄对对象进行排序,若返回负数,当前对象的年龄比被比较对象年龄小,排序方法会将较小的放在前面
public int compareTo(Object o) {
int result;
result = this.age - ((User) o).getAge();
return result;
}
public static void main(String[] args) {
User[] userArray = new User[] {new User("0003",19),new User("0004",21),new User("0009",17)};
Arrays.sort(userArray);
//排序结果为("0009",17),("0003",19),("0004",21)
}
}

  Comparator接口使用示例:

public class User {
private String id;
private int age;
public User(String id, int age) {
this.id = id;
this.age = age;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}

public class NewComparator implements Comparator<Object>{

//该方法返回一个基本类型的整型,返回负数表示o1 小于o2,返回0 表示o1和o2相等,返回正数表示o1大于o2。 
//在对象外部定义排序规则
public int compare(Object o1, Object o2) {
User u1 = (User) o1;
User u2 = (User) o2;
return u1.getAge() - u2.getAge();
}

}

public class TestSort {

public static void main(String[] args) {
User[] userArray = new User[] {new User("0003",19),new User("0004",21),
new User("0009",17)};
//由于User没有实现Comparable接口,需要使用一个比较器来对对象进行比较
Arrays.sort(userArray,new NewComparator());
//排序结果为:("0009",17),("0003",19),("0004",21)
}

}

总结及比较

  Comparable是通用的接口,用户可以实现它来完成自己特定的比较,而Comparator可以看成一种算法的实现,在需要容器集合collection需要比较功能的时候,来指定这个比较器,这可以看出一种设计模式,将算法和数据分离。
  前者应该比较固定,和一个具体类相绑定,而后者比较灵活,它可以被用于各个需要比较功能的类使用。可以说前者属于“静态绑定”,而后者可以“动态绑定”。
  一个类实现了Camparable接口表明这个类的对象之间是可以相互比较的。如果用数学语言描述的话就是这个类的对象组成的集合中存在一个全序。这样,这个类对象组成的集合就可以使用Sort方法排序了。
  而Comparator的作用主要是以下两个:
  1)如果类的设计师没有考虑到Compare的问题而没有实现Comparable接口,可以通过Comparator来实现比较算法进行排序。
  2)为了使用不同的排序标准做准备,比如:升序、降序或其他什么序。

4.参考

http://viver120.blog.163.com/blog/static/60072482013010111228695/
http://blog.csdn.net/sdliubo/article/details/7332940
http://blog.sina.com.cn/s/blog_4fb846a90100d8q0.html
http://www.cnblogs.com/nktblog/articles/2517095.html

一个更复杂的排序例子
http://blog.csdn.net/qimiguang/article/details/13510151

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值