简介:java的排序可以通过Collections.sort(LIst)和Arrays.sort(Array)进行实现,总的看来大体的实现方式有两种,一种是排序对象自身实现Comparable接口, 另外一种就是在使用sort方法是传入第二个参数Comparator.
跟c,c++中的cmp函数一样, java也需要方法来对比两个对象的大小,cmp的实现由两种方式,一种实现Comparable接口的类,通过实现compareTo方法来对比对象的大小。第二种方法Comparator接口中通过实现compare方法来满足该要求。 在排序过程中equals方法不是必须的。
一、用Comparable接口实现排序
import java.text.Collator;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class User implements Comparable<Object>{
private static Collator cmp = Collator.getInstance();
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
@Override
public int compareTo(Object o) {
User u = (User)o;
return cmp.compare(this.username, u.getUsername());
}
public static void main(String[] args) {
List<User> us = new ArrayList<User>();
us.add(new User("chuninsane", "123"));
us.add(new User("boas", "123"));
us.add(new User("gg", "123"));
Collections.sort(us);
for(User u: us) {
System.out.println(u.getUsername());
}
}
}
上面的compareTo方法中使用Collator中的compare来对User的username进行比较, 最后比较的结果是按照username的字典序进行排序
现在来分析一下Collections.sort方法的源码
public static <T extends Comparable<? super T>> void sort(List<T> list) {
Object[] a = list.toArray();
Arrays.sort(a);
ListIterator<T> i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set((T)a[j]);
}
}
从上面可以清楚看出,Collections.sort方法也调用了Arrays.sort方法, 将list先转换为Array,然后排序结束之后再将数据复制回list中
下面我们接着分析Arrays.sort方法
public static void sort(Object[] a) {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a);
else
ComparableTimSort.sort(a);
}
LegacyMergeSort.userRequested参数决定是采用MergeSort还是使用TimeSort来进行排序
LegacyMergeSort.userRequested由"java.util.Arrays.useLegacyMergeSort"方法进行设置
legacyMergeSort方法的源码
private static void legacyMergeSort(Object[] a) {
Object[] aux = a.clone();
mergeSort(aux, a, 0, a.length, 0);
}
legacyMergeSort又调用merge进行排序
private static void mergeSort(Object[] src,
Object[] dest,
int low,
int high,
int off) {
int length = high - low;
if (length < INSERTIONSORT_THRESHOLD) {
for (int i=low; i<high; i++)
for (int j=i; j>low &&
((Comparable) dest[j-1]).compareTo(dest[j])>0; j--)
swap(dest, j, j-1);
return;
}
int destLow = low;
int destHigh = high;
low += off;
high += off;
int mid = (low + high) >>> 1;
mergeSort(dest, src, low, mid, -off);
mergeSort(dest, src, mid, high, -off);
if ((<span style="color:#ff0000;">(Comparable)src[mid-1]).compareTo(src[mid])</span> <= 0) {
System.arraycopy(src, low, dest, destLow, length);
return;
}
for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
if (q >= high || p < mid && (<span style="color:#ff0000;">(Comparable)src[p]).compareTo(src[q])</span><=0)
dest[i] = src[p++];
else
dest[i] = src[q++];
}
}
顾名思义, mergeSort就是归并排序,将dest分成
INSERTIONSORT_THRESHOLD大小的多个子串, 然后采用选择排序对子串进行排序,最后进行整理
上面代码中需要注意的就是((Comparable)src[mid-1]).compareTo(src[mid]) <= 0, 表示两个子串可以直接连接起来。否则就采用归并排序的合并方式进行合并。
②ComparableTimSort.sort方法的源码
static void sort(Object[] a) {
sort(a, 0, a.length);
}
static void sort(Object[] a, int lo, int hi) {
rangeCheck(a.length, lo, hi);
int nRemaining = hi - lo;
if (nRemaining < 2)
return;
if (nRemaining < MIN_MERGE) {
int initRunLen = countRunAndMakeAscending(a, lo, hi);
binarySort(a, lo, hi, lo + initRunLen);
return;
}
ComparableTimSort ts = new ComparableTimSort(a);
int minRun = minRunLength(nRemaining);
do {
int runLen = countRunAndMakeAscending(a, lo, hi);
if (runLen < minRun) {
int force = nRemaining <= minRun ? nRemaining : minRun;
binarySort(a, lo, lo + force, lo + runLen);
runLen = force;
}
ts.pushRun(lo, runLen);
ts.mergeCollapse();
lo += runLen;
nRemaining -= runLen;
} while (nRemaining != 0);
assert lo == hi;
ts.mergeForceCollapse();
assert ts.stackSize == 1;
}
TimSort是一个归并排序做了大量优化的排序方式
此方法中传入的带排序数组长度若小于阀值MIN_MERGE,则调用binarySort方法, 然后开始真正的TimSort方法的处理(待补充)
二、用Comparator实现排序
jdk中对该接口的描述:
强行对某个对象 collection 进行整体排序 的比较函数。可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用 Comparator 来控制某些数据结构(如有序 set或有序映射)的顺序,或者为那些没有自然顺序的对象 collection
提供排序。
在Set和Map中Comparator的用法
Comparator的定义
import java.text.Collator;
import java.util.Comparator;
public class UserComparator implements Comparator<User> {
Collator cmp = Collator.getInstance();
@Override
public int compare(User o1, User o2) {
return cmp.compare(o1.getUsername(), o2.getUsername());
}
}
使用Comparator进行排序
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class User {
private String username;
private String password;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public User(String username, String password) {
this.username = username;
this.password = password;
}
public static void main(String[] args) {
List<User> us = new ArrayList<User>();
us.add(new User("aaa", "123"));
us.add(new User("bbb", "123"));
us.add(new User("aaa", "123"));
Collections.sort(us, new UserComparator());
for(User u: us) {
System.out.println(u.getUsername());
}
}
}
首先还是查看Collections.sort的源码
public static <T> void sort(List<T> list, Comparator<? super T> c) {
Object[] a = list.toArray();
Arrays.sort(a, (Comparator)c);
ListIterator i = list.listIterator();
for (int j=0; j<a.length; j++) {
i.next();
i.set(a[j]);
}
}
这里还是调用的Arrays.sort方法
public static <T> void sort(T[] a, Comparator<? super T> c) {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, c);
else
TimSort.sort(a, c);
}
上面的方法还是和Comparable中的类似
private static <T> void legacyMergeSort(T[] a, Comparator<? super T> c) {
T[] aux = a.clone();
if (c==null)
mergeSort(aux, a, 0, a.length, 0);
else
mergeSort(aux, a, 0, a.length, 0, c);
}
merge的源码
private static void mergeSort(Object[] src,
Object[] dest,
int low, int high, int off,
Comparator c) {
int length = high - low;
if (length < INSERTIONSORT_THRESHOLD) {
for (int i=low; i<high; i++)
for (int j=i; j>low && <span style="color:#ff0000;">c.compare(dest[j-1], dest[j])</span>>0; j--)
swap(dest, j, j-1);
return;
}
int destLow = low;
int destHigh = high;
low += off;
high += off;
int mid = (low + high) >>> 1;
mergeSort(dest, src, low, mid, -off, c);
mergeSort(dest, src, mid, high, -off, c);
if (c.compare(src[mid-1], src[mid]) <= 0) {
System.arraycopy(src, low, dest, destLow, length);
return;
}
for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
if (q >= high || p < mid && c.compare(src[p], src[q]) <= 0)
dest[i] = src[p++];
else
dest[i] = src[q++];
}
}
从上面的merge可以看出Comparable个Comparator的最大区别就是在进行对象对比时用的方法不同, Comparable中将对象强制转换为Comparable类型,如果你的类没实现Comparable接口则会报
java.lang.ClassCastException
XXXDO cannot be cast to java.lang.Comparable错误, Comparator则中则是调用传入的Comparator中的compare方法来比较两个对象的大小。
——结束