浅谈 Java 自定义排序之 Comparator

  排序是编程中经常需要用到的功能,而 Java 的工具类 Collections 中也提供了 sort 方法用于实现对列表等集合中元素的排序。Collections.sort() 方法有两种形式:Collections.sort(List)Collections.sort(List, Comparator)

  第一种 Collections.sort(List) 要求 List 中的元素已经实现了 Comparable 接口,第二种 Collections.sort(List, Comparator) 则需要实现一个比较器。基于比较的排序的关键就是能比较两个元素的大小,知道了谁大谁小,才能确定谁排在前面谁排在后面;而这两种方法的本质都是为了确定两个元素谁大谁小。接下来主要谈一谈基于比较器的自定义排序。

  先看个排序示例:

public static void main(String[] args) {
	Integer[] input = { 1, 3, 8, 7, 4, 9, 2 };        
	List<Integer> lst = Arrays.asList(input);
	
	Collections.sort(lst);
	System.out.println(lst);
}
//输出为: [1, 2, 3, 4, 7, 8, 9]

  可以看到,原本无序的列表变成了从小到大排列。原因有二:

  1. Integer 类实现了 Comparable 接口,使得元素之间可以比较大小
  2. sort 方法默认是从小到大排列(这点非常重要)

  然而大多数情况下,我们想要的都不是简单的升序排列,这时候自定义排序就要派上用场了。Comparator 实现自定义排序的关键是实现 compare 方法,该方法声明为:

int compare(T o1, T o2);

当方法返回负值时,代表 o1 < o2;当方法返回 0 时,代表 o1 = o2;当方法返回正值时,代表 o1 > o2;下面以实现降序排列为例,演示如何使用 Comparator。

###一、降序排列

public class Main {
    public static void main(String[] args) {
        Integer[] input = { 1, 3, 8, 7, 4, 9, 2 };        
        List<Integer> lst = Arrays.asList(input);
        
        Collections.sort(lst, new IntComparator<Integer>());
        System.out.println(lst);
    }
}

class IntComparator<T> implements Comparator<T> {
    public int compare(T a, T b) {
        return (Integer)b - (Integer)a;
    }
}
//输出为: [9, 8, 7, 4, 3, 2, 1]

  为什么这样就实现了降序排列呢?

  这是因为当传入 Comparator 参数时, sort 方法会将需要比较大小的两个元素 a,b 作为参数传给 Comparator.compare(T a, T b) 方法,根据返回的结果判断 a,b 的大小。例如,传入1 和 3 的时候,compare 返回 2,正值代表 a > b,即 1 “大于” 3,这个“大于”正是我们自己定义的规则。然后,根据 sort 方法默认从小到大排序的性质,小的排在前面,所以最后 3 排在 1 前面,也就实现了降序排列。

  在这里 return (Integer)b - (Integer)a; 是一种经验写法,如果分解开来应该是这样:

class IntComparator<T> implements Comparator<T> {
    public int compare(T a, T b) {
        int num1 = (Integer)a;
        int num2 = (Integer)b;
        
        if(num1 > num2) { //如果 a>b,根据自定义规则 a 应该在前面,即自定义规则中 a “小于” b,故此时返回负值
            return -1;
        } else if(num1 < num2) {
            return 1;
        } else {
            return 0;
        }
    }
}

  该 compare 方法非常简单,但在实际应用中,由于自定义规则的复杂性,compare 的编写难度也可能变得很大。下面再举一例,让大家加深对 compare 的理解。

###二、奇偶排列   要求:奇数排在偶数前面,奇数之间从小到大排列,偶数之间从大到小排序

class IntComparator<T> implements Comparator<T> {
    public int compare(T a, T b) {
        int num1 = (Integer)a;
        int num2 = (Integer)b;
        if(num1 % 2 == 1 && num2 % 2 == 1) {
            return num1 - num2; // ①
        } else if(num1 % 2 == 0 && num2 % 2 == 0) {
            return num2 - num1; // ②
        } else if(num1 % 2 == 1 && num2 % 2 == 0) {
            return -1; // ③
        } else {
            return 1; // ④
        }
    }
}

  ① ② 表示两数同奇或同偶的情况,此时根据经验写法很容易得到。

  ③ ④ 表示奇偶不同的情况,此时若 a 为奇数,b 为偶数,则 a 应该排在 b 前面,即 a “小于” b,故返回负值;反之,返回正值。

  最后,再次强调:排在前面的元素“小”,排在后面的元素“大”

  留个练习,有兴趣的朋友可以做下,看看自己是不是真的掌握了。

  练习题:实现数字按照高位到低位的比较,进行降序排序;高位相同的,位数少的排前面。例如:输入 {3, 34, 5, 7, 56, 523, 52, 571};输出 {7, 5, 571, 56, 52, 523, 3, 34}

转载于:https://my.oschina.net/amstrong/blog/753990

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值