java 容器中排序算法的源码实现分析(京东电话面试)

排序算法源码剖析

首先在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接口设定的排序方式。
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]


从结构上分析:Comparable 接口只有 public int compareTo(T o) 方法,Comparator 有   int   compare(T   o1,   T   o2)和   boolean   equals(Object   obj)
有时并没有实现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;
		}
	}
	
}










  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值