排序算法源码剖析
首先在eclipse 中使用Ctrl+鼠标左键查看源码发现 source not found ,出现这个问题很简单就是源码没有连接。把JDK 安装时的src.zip连接就可以
具体参考百度经验:http://jingyan.baidu.com/article/22a299b5234ecb9e19376ae1.html
首先说下Collections下面sort 方法两个使用场景。
场景一:对java 内置类型比如String、Integer 等进行排序,因为这些类型已经implements Comparable接口,所以这些类型排序最简单直接。
package javaUsage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class LearningSortMethod {
public static void main(String[] args){
List<String> list = new ArrayList<>();
String[] strs = {"hello","world","good"};
for(String str:strs){
list.add(str);
}
System.out.println(list);
Collections.sort(list);
System.out.println(list);
Collections.reverse(list);
System.out.println(list);
}
}
输出结果:
[hello, world, good]
[good, hello, world]
[world, hello, good]
场景二:需要对自定义的对象就行排序,这是有两种方法。
方法1:自定义类implements Comparable并且重写 compareTo方法
构造了一个学生类,根据学生分数进行排名输出,见代码
package javaUsage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class LearningSortMethod {
public static void main(String[] args){
List<StudentInof> list = new ArrayList<>();
StudentInof[] stus = {new StudentInof("alice", 85.0),new StudentInof("Tony", 75.0),
new StudentInof("Bob", 99.0)};
for(StudentInof stu:stus){
list.add(stu);
}
Collections.sort(list);
System.out.println(list);
Collections.reverse(list);
System.out.println(list);
}
}
class StudentInof implements Comparable<Object>{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Double getScore() {
return score;
}
public void setScore(Double score) {
this.score = score;
}
private Double score;
public StudentInof(String name,Double score){
this.name = name;
this.score = score;
}
@Override
public int compareTo(Object o) {
StudentInof stu = (StudentInof) o;
Double otherScore = stu.getScore();
return this.score.compareTo(otherScore);
}
public String toString(){
return "name:"+this.getName() + " score:"+ this.getScore();
}
}
升序和逆序分别输出:
[name:Tony score:75.0, name:alice score:85.0, name:Bob score:99.0]
[name:Bob score:99.0, name:alice score:85.0, name:Tony score:75.0]
方法 2 :自己定义一个比较器类实现Comparator接口,然后Collections sort 方法传入比较器实例作为第二个参数
package javaUsage;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class LearningSortMethod {
public static void main(String[] args){
/**
List<StudentInof> list = new ArrayList<>();
StudentInof[] stus = {new StudentInof("alice", 85.0),new StudentInof("Tony", 75.0),
new StudentInof("Bob", 99.0)};
for(StudentInof stu:stus){
list.add(stu);
}
Collections.sort(list);
System.out.println(list);
Collections.reverse(list);
System.out.println(list);
*/
List<TeacherInfo> list = new ArrayList<>();
TeacherInfo[] techs = {new TeacherInfo(22, "shang"),new TeacherInfo(32, "chen"),
new TeacherInfo(18, "lin"),new TeacherInfo(10, "hu")};
for(TeacherInfo tech:techs){
list.add(tech);
}
MyCompartor mc = new MyCompartor();
Collections.sort(list, mc);
System.out.println(list);
}
}
class TeacherInfo {
private Integer age;
// Integer 类中 implements 了接口,而int 类型没有
public Integer getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
private String name;
public TeacherInfo(int age,String name){
this.age = age;
this.name = name;
}
public String toString(){
return "name:"+this.getName() + " age:"+ this.getAge();
}
}
class MyCompartor implements Comparator<Object>{
@Override
public int compare(Object o1, Object o2) {
// 根据Teacher信息age 排序
TeacherInfo t1 = (TeacherInfo)o1;
TeacherInfo t2 = (TeacherInfo)o2;
return t1.getAge().compareTo(t2.getAge());
}
}
升序和逆序排序输出:
[name:hu age:10, name:lin age:18, name:shang age:22, name:chen age:32]
上面主要还是涉及如何使用,下面主要涉及实现源码(JDK 1.7)部分:
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]);
}
}
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]);
}
}
查看了这两个方法参数就明白为什么需要implements Comparable接口或者 创建自己 Comparator类。
当然还可以发现一个问题 Collections sort 方法底层其实就是 Arrays 的sort 方法,接下来继续看Arrays 的sort 方法。
public static void sort(Object[] a) {
if (LegacyMergeSort.userRequested)
legacyMergeSort(a);
else
ComparableTimSort.sort(a);
}
private static void legacyMergeSort(Object[] a) {
Object[] aux = a.clone();
mergeSort(aux, a, 0, a.length, 0);
}
核心是mergeSort函数
private static void mergeSort(Object[] src,
Object[] dest,
int low,
int high,
int off) {
int length = high - low;
// Insertion sort on smallest arrays
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;
}
// Recursively sort halves of dest into src
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 list is already sorted, just copy from src to dest. This is an
// optimization that results in faster sorts for nearly ordered lists.
if (((Comparable)src[mid-1]).compareTo(src[mid]) <= 0) {
System.arraycopy(src, low, dest, destLow, length);
return;
}
// Merge sorted halves (now in src) into dest
for(int i = destLow, p = low, q = mid; i < destHigh; i++) {
if (q >= high || p < mid && ((Comparable)src[p]).compareTo(src[q])<=0)
dest[i] = src[p++];
else
dest[i] = src[q++];
}
}
所以可以确定一个事情就是 Collections 排序和Arrays 排序都是底层 mergeSort实现,但是文档也说了,不一定必须要是mergesort但是必须要是稳定的排序算法。
Comparable & Comparator
前面排序多次出现了这两个接口,这里把这两个接口总结下。
首先是 两个接口 Comparator位于包java.util下,而Comparable位于包 java.lang下 ,前面实例代码也看到了 这两个接口的功能: Comparable & Comparator 都是用来实现集合中元素的比较、排序的,只是 Comparable 是在集合内部定义的方法实现的排序,Comparator 是在集合外部实现的排序,所以,如想实现排序,就需要在集合外定义 Comparator 接口的方法或在集合内实现 Comparable 接口的方法。
Comparable 是一个对象本身就已经支持自比较所需要实现的接口(如 String、Integer 自己就可以完成比较大小操作,已经实现了Comparable接口),这也是为什么容器中存放String 或者Integer类型不需要额外操作因为本身类已经实现了Comparable 接口。
自定义的类要在加入list容器中后能够排序,可以实现Comparable接口,在用Collections类的sort方法排序时,如果不指定Comparator,那么就以自然顺序排序,如API所说:
Sorts the specified list into ascending order, according to the natural ordering of its elements. All elements in the list must implement the Comparable interface
这里的自然顺序就是实现Comparable接口设定的排序方式。
Sorts the specified list into ascending order, according to the natural ordering of its elements. All elements in the list must implement the Comparable interface
这里的自然顺序就是实现Comparable接口设定的排序方式。
Comparator 是一个专用的比较器,当这个对象不支持自比较或者自比较函数不能满足你的要求时,你可以写一个比较器来完成两个对象之间大小的比较。
Comparator 是策略模式(strategy design pattern),就是不改变对象自身,而用一个策略对象(strategy object)来改变它的行为
举个示例代码:
比如:你想对整数采用绝对值大小来排序,Integer 是不符合要求的,你不需要去修改 Integer 类(实际上你也不能这么做)去改变它的排序行为,只要使用一个实现了 Comparator 接口的对象来实现控制它的排序就行了。
package javaUsage;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Random;
public class TestComparator {
public static void main(String[] args) {
Random rnd = new Random();
Integer[] integers = new Integer[20];
for (int i = 0; i < integers.length; i++)
integers[i] = new Integer(rnd.nextInt(100)
* (rnd.nextBoolean() ? 1 : -1));
System.out.println("用Integer内置方法排序:");
Arrays.sort(integers);
System.out.println(Arrays.asList(integers));
System.out.println("用AbsComparator排序:");
Arrays.sort(integers, new AbsComparator());
System.out.println(Arrays.asList(integers));
}
}
class AbsComparator implements Comparator<Object> {
public int compare(Object o1, Object o2) {
int v1 = Math.abs(((Integer) o1).intValue());
int v2 = Math.abs(((Integer) o2).intValue());
return v1 > v2 ? 1 : (v1 == v2 ? 0 : -1);
}
}
输出:
用Integer内置方法排序:
[-92, -88, -84, -84, -74, -63, -56, -26, -19, 29, 35, 52, 73, 78, 79, 79, 83, 87, 90, 99]
用AbsComparator排序:
[-19, -26, 29, 35, 52, -56, -63, 73, -74, 78, 79, 79, 83, -84, -84, 87, -88, 90, -92, 99]
有时并没有实现equals 方法,那是因为 继承了Object 的 equals 方法。
Comparable接口只提供了 int compareTo(T o)方法,也就是说假如我定义了一个Person类,这个类实现了 Comparable接口,那么当我实例化Person类的person1后,我想比较person1和一个现有的Person对象person2的大小时,我就可以这样来调用:person1.comparTo(person2),通过返回值就可以判断了;而此时如果你定义了一个 PersonComparator(实现了Comparator接口)的话,那你就可以这样:PersonComparator comparator= new PersonComparator(); comparator.compare(person1,person2);
京东在线笔试编程题
题目抽象出来就是给一个m*2的数组排序,排序规则就是如果两个数都大或者都小那么可以排序,如果两个数中一大一小,则保持原先顺序。
package contest;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
// 京东在线编程题
public class MaxLetters {
public static void ShowInfo(int letters[][]){
for(int i=0;i<letters.length;i++){
System.out.println(letters[i][0]+":"+letters[i][1]);
}
System.out.println("------");
}
public static int FindIndex(int[]letter,int[][]letters){
int i ;
for(i=0;i<letters.length;i++){
if(letters[i][0]==letter[0] && letters[i][1]==letter[1]){
break;
}
}
return i;
}
public static void main(String[] args) {
int n,w,h;
@SuppressWarnings("resource")
Scanner sc = new Scanner(System.in);
while(sc.hasNext()){
n = sc.nextInt();
w = sc.nextInt();
h = sc.nextInt();
int [][]letters = new int[n][2];
int [][]copy = new int[n][2];
for(int i=0;i<n;i++){
letters[i] = new int[2];
copy[i] = new int[2];
letters[i][0] = sc.nextInt();
letters[i][1] = sc.nextInt();
copy[i][0] = letters[i][0];
copy[i][1] = letters[i][1];
}
ShowInfo(letters);
ShowInfo(copy);
Mycomparator my = new Mycomparator();
Arrays.sort(letters,my);
ShowInfo(letters);
int index = 0;
int count = 0;
int []res = new int[letters.length];
for(int i=0;i<letters.length;i++){
for(int j=index;j<letters.length;j++){
if(w < letters[j][0] && h < letters[j][1]){
res[count] = FindIndex(letters[j], copy)+1;
count++;
index = j;
w = letters[j][0];
h = letters[j][1];
}
}
}
if(count == 0){
System.out.println(0);
}else{
System.out.println(count);
for(int i=0;i<count;i++){
System.out.print(res[i]+" ");
}
System.out.println();
}
}
}
}
class Mycomparator implements Comparator<Object>{
@Override
public int compare(Object o1, Object o2) {
int[] letter1 = (int[])o1;
int[] letter2 = (int[])o2;
if(letter1[0] > letter2[0] && letter1[1] < letter2[1]){
return 1;
}
else if(letter1[0] < letter2[0] && letter1[1] < letter2[1]){
return -1;
}else{
return 0;
}
}
}