非基本类型实现比较
Comparator 接口
表明这是一个排序器,提供了对其中的泛型元素进行排序的方法。
Comparable 接口
表明这个元素自身带有可排序的方法,这是一个可排序的元素。
定义外部比较器
实现 Comparator 接口
定义外部比较器的方式实现比较是很灵活的,我们可以对指定的元素建立不同的比较器来实现不同的比较策略而不用考虑其他的因素。比如说:分别建立按照ID 升序、降序排序的排序器,这样我们在实现排序方法的时候就不用考虑排序策略,只专注于排序算法。
主要是实现Comparator中的 int compare(T o1, T o2); 方法, 外部使用比较器进行元素比较的时候会使用这个方法来进行元素之间的比较
public class ComparableTestData implements Comparator<TestData> {
@Override
public int compare(TestData o1, TestData o2) {
if (o1.getAge() > o2.getAge()) {
return -1;
} else if (o1.getAge() < o2.getAge()) {
return 1;
}
return 0;
}
}
code
public class DemoB {
public static void main(String[] args) {
ArrayList<TestData> list = new ArrayList<>();
list.add(new TestData(1, "aa", Collections.emptyList()));
list.add(new TestData(2, "bb", Collections.emptyList()));
list.add(new TestData(4, "dd", Collections.emptyList()));
list.add(new TestData(5, "ee", Collections.emptyList()));
list.add(new TestData(3, "cc", Collections.emptyList()));
System.out.println("---------> 排序前");
list.forEach(System.out::println);
// Collections.sort(list, TestData::compareTo);
Collections.sort(list, new ComparableTestData());
System.out.println("---------> 排序后");
list.forEach(System.out::println);
}
}
待比较元素指定比较方法
带比较元素实现 Comparable 接口
另外一种方法就是我们待比较元素自己指定比较方法,也就是本身就支持排序,实现方法为实现Comparable接口
public class TestData<Inner> implements Comparable<TestData> {
private Integer age;
private String name;
private List<Inner> inners;
@Override
public int compareTo(TestData o) {
if (o.age > this.age) {
return 1;
} else if (o.age.equals(this.age)) {
return 0;
} else {
return -1;
}
}
}
code
public class DemoA {
public static void main(String[] args) {
ArrayList<TestData> list = new ArrayList<>();
list.add(new TestData(1, "aa", Collections.emptyList()));
list.add(new TestData(2, "bb", Collections.emptyList()));
list.add(new TestData(4, "dd", Collections.emptyList()));
list.add(new TestData(5, "ee", Collections.emptyList()));
list.add(new TestData(3, "cc", Collections.emptyList()));
System.out.println("---------> 排序前");
list.forEach(System.out::println);
Collections.sort(list);
System.out.println("---------> 排序后");
list.forEach(System.out::println);
}
}
探究 Comparator Comparable 中的比较方法如何调用的
以使用 Collections.sort 方法为例进行原理探究
探究提供比较器
实现 implements Comparator
- 需要传递 排序器
- 排序器是 Comparator 类型
- 并且内部泛型要为 待排序集合中的类型
- 排序器是 Comparator 类型
此时的sost方法是 Collections 接口中的,它的具体实现由具体的集合类做出, 此时需要查看ArrayList的sort方法
public static <T> void sort(List<T> list, Comparator<? super T> c) {
list.sort(c);
}
ArrayList.sort
可以看到内部使用 Arrays.sort进行排序, 在并发环境下会抛出并发异常。
@Override
@SuppressWarnings("unchecked")
public void sort(Comparator<? super E> c) {
final int expectedModCount = modCount;
Arrays.sort((E[]) elementData, 0, size, c);
if (modCount != expectedModCount) {
throw new ConcurrentModificationException();
}
modCount++;
}
Arrays.sort((E[]) elementData, 0, size, c);
这里排序实现中,可以根据是否传递排序器,分别实现做出不同的排序实现。
public static <T> void sort(T[] a, int fromIndex, int toIndex,
Comparator<? super T> c) {
if (c == null) {
// 没有传递排序器
sort(a, fromIndex, toIndex);
} else {
// 传递排序器, 进行范围检查
rangeCheck(a.length, fromIndex, toIndex);
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, fromIndex, toIndex, c);
else
// 会直接走到这里
TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
}
}
TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
在这里排序实现中, 最后会调用 **binarySort(a, lo, hi, lo + initRunLen, c);**进行实现。
static <T> void sort(T[] a, int lo, int hi, Comparator<? super T> c,
T[] work, int workBase, int workLen) {
assert c != null && a != null && lo >= 0 && lo <= hi && hi <= a.length;
int nRemaining = hi - lo;
if (nRemaining < 2)
return; // Arrays of size 0 and 1 are always sorted
// If array is small, do a "mini-TimSort" with no merges
if (nRemaining < MIN_MERGE) {
int initRunLen = countRunAndMakeAscending(a, lo, hi, c);
binarySort(a, lo, hi, lo + initRunLen, c);
return;
}
}
binarySort
在 binarySort 方法中就可以看到调用我们传递进来的排序器进行元素之间的大小比较了。
private static <T> void binarySort(T[] a, int lo, int hi, int start,
Comparator<? super T> c) {
assert lo <= start && start <= hi;
if (start == lo)
start++;
for ( ; start < hi; start++) {
T pivot = a[start];
// Set left (and right) to the index where a[start] (pivot) belongs
int left = lo;
int right = start;
assert left <= right;
/*
* Invariants:
* pivot >= all in [lo, left).
* pivot < all in [right, start).
*/
while (left < right) {
int mid = (left + right) >>> 1;
// 这里将会调用我们外部排序器的排序方法进行元素的排序
if (c.compare(pivot, a[mid]) < 0)
right = mid;
else
left = mid + 1;
}
}
元素本身提供排序方法
元素实现 implements Comparable
此时没有传递排序器, list.sort(null); 此时是在Collection中, 联系上面的分析,我们可以直接跳到 Arrays.sort((E[]) elementData, 0, size, c); 中
public static <T extends Comparable<? super T>> void sort(List<T> list) {
list.sort(null);
}
- 此时是没有传递排序器, 进行 sort(a, fromIndex, toIndex);
public static <T> void sort(T[] a, int fromIndex, int toIndex,
Comparator<? super T> c) {
if (c == null) {
// 没有传递排序器
sort(a, fromIndex, toIndex);
} else {
// 传递排序器, 进行范围检查
rangeCheck(a.length, fromIndex, toIndex);
if (LegacyMergeSort.userRequested)
legacyMergeSort(a, fromIndex, toIndex, c);
else
// 会直接走到这里
TimSort.sort(a, fromIndex, toIndex, c, null, 0, 0);
}
}
Arrays.sort
public static void sort(Object[] a) {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a);
else
// 开始调用这个方法
ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
}
ComparableTimeSort.sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen)
这里开始对元素进行排序了,在 binarySort 方法中可探究到最终的实现
static void sort(Object[] a, int lo, int hi, Object[] work, int workBase, int workLen) {
assert a != null && lo >= 0 && lo <= hi && hi <= a.length;
int nRemaining = hi - lo;
if (nRemaining < 2)
return; // Arrays of size 0 and 1 are always sorted
// If array is small, do a "mini-TimSort" with no merges
if (nRemaining < MIN_MERGE) {
int initRunLen = countRunAndMakeAscending(a, lo, hi);
binarySort(a, lo, hi, lo + initRunLen);
return;
}
}
ComparableTimeSort.binarySort
在binarySort 方法中我们就可以直接看到实际的操作是把 待排序元素转化为Comparable ,然后使用其排序方法进行排序
private static void binarySort(Object[] a, int lo, int hi, int start) {
assert lo <= start && start <= hi;
if (start == lo)
start++;
for ( ; start < hi; start++) {
// 把元素转化为 Comparable
Comparable pivot = (Comparable) a[start];
// Set left (and right) to the index where a[start] (pivot) belongs
int left = lo;
int right = start;
assert left <= right;
/*
* Invariants:
* pivot >= all in [lo, left).
* pivot < all in [right, start).
*/
while (left < right) {
int mid = (left + right) >>> 1;
// 开始调用 待排序对象自己实现的排序方法
if (pivot.compareTo(a[mid]) < 0)
right = mid;
else
left = mid + 1;
}
}
总结
- 实现排序的方法
- 新建排序器
- 待排序元素自身支持排序
- Conllections.sort 使用的 Arrays.sort 为自己实现
- Arrays.sort