浅析Collections.sort

问题引入

  在之前的一次Java上机实习中,老师布置了一道很简单的题:

从控制台输入10个整数,对它们进行升序排序并输出。

  考虑到只有10个数,需要比较的次数不是很多,所以当时我自己写了一段冒泡排序的算法然后就上交作业。交作业之后我突然想到一个问题:JDK是否有类似于STL中的std::sort方法,能实现基本的排序而无需用户自己实现?

Collections.sort简介

  第9版《Java核心技术卷Ⅰ》的第607页介绍了一个方法:

Collections类中的sort方法可以对实现了List接口的集合进行排序。这个方法假定列表元素实现了Comparable接口。

  查看Java官方文档可知,sort方法有两种重载形式。第一种重载是:

static <T extends Comparable<? super T>> void sort(List<T> list)

  根据官方文档的描述,这个方法将列表元素进行升序排序,但是列表要满足以下条件:
  1.列表元素实现了Comparable接口,且任意两个列表元素都是可比的。
  2.列表必须支持set方法。
  如果要通过这个方法来完成我上面提到的作业,那显然是行得通的:整数可以进行相互比较,第一个条件满足;把10个整数放入一个ArrayList或LinkedList中,这两个列表都支持set方法,第二个条件满足。实现代码如下:

import java.util.*;
public class Sort { public static void main(String[] args) { Scanner scan = new Scanner(System.in);
List<Integer> list = new ArrayList<>(); //用户输入10个整数
System.out.println("请输入10个整数:");
for(int i = 0; i < 10; i++)
{
list.add(scan.nextInt());
}
scan.close(); //排序
Collections.sort(list); //输出排序结果
System.out.println(list);
} }

  程序运行结果如下:

 
用sort进行升序排序

  用sort方法可以很方便地实现升序排序,但能否进行降序排序?答案是肯定的,《Java核心技术卷Ⅰ》中介绍了一种用sort进行降序排序的简洁方法。这种方法需要用到sort方法的第二种重载形式:

public static <T> void sort(List<T> list,Comparator<? super T> c)

  如果想采用其他方式进行排序,那么可将一个Comparator对象作为sort方法的第二个参数。当要进行逆序排序时,最简便的方法是将Collections.reverseOrder()作为第二个参数。

import java.util.*;
public class Sort { public static void main(String[] args) { Scanner scan = new Scanner(System.in);
List<Integer> list = new ArrayList<>(); //用户输入10个整数
System.out.println("请输入10个整数:");
for(int i = 0; i < 10; i++)
{
list.add(scan.nextInt());
}
scan.close(); //逆序排序
Collections.sort(list,Collections.reverseOrder()); //输出排序结果
System.out.println(list);
} }

  程序运行结果如下:

 
用sort进行降序排序

更进一步:排序对象不是基本数据类型

  在上面的例子中,列表中的元素是整数,所以排序逻辑是很显然的:如果是升序排序,那就小数在前,大数在后。但是,如果排序的对象并非属于整数、浮点数之类的基本数据类型,那么这些对象之间的“大小”关系该如何定义?假设有这样一道题:

定义一个点类,其中有整型属性x和y,代表其坐标;除了这两个属性以外没有其他属性。随机产生10个点,并按照这些点与原点(0,0)之间的距离大小对点进行降序排序。

  如果仍想通过sort方法进行排序的话,首先点类就必须满足上面曾经提过的约束条件:点对象是可比的,因此点类必须实现Comparable接口。查看官方文档可知,Comparable接口中只有一个方法:

int compareTo(T o)

  调用这个方法的对象将会与参数o进行比较,小于o、等于o和大于o分别对应的返回值为负数、0和正数。对象之间相对大小的判断方法是自定义的,在这个问题中,就是通过比较各点与原点之间的距离来判断大小,所以点类的实现如下:

class Point implements Comparable<Point>{

    private int x;
private int y; public Point(int x,int y)
{
this.x = x;
this.y = y;
} @Override
//如果该点到原点的距离大于o点到原点的距离,则该点大于o点
public int compareTo(Point o) { int distance1 = (this.x) * (this.x) + (this.y) * (this.y);
int distance2 = (o.x) * (o.x) + (o.y) * (o.y); return (distance1 > distance2) ? 1 : ((distance1 == distance2) ? 0 : -1);
} @Override
public String toString() {
return "(" + x + ","+ y + ")";
}
}

  因为要进行降序排序,所以可以通过将Collections.reverseOrder()作为sort方法的第二个参数来实现:

public class SortDemo {

    private static List<Point> list = new ArrayList<>();

    public static void main(String[] args) {

        //随机生成10个点
for(int i = 0; i < 10; i++)
{
//点的坐标取值在[1,20]之间
int x = (int)(Math.random() * 20) + 1;
int y = (int)(Math.random() * 20) + 1; list.add(new Point(x,y));
}
System.out.print("排序前:");
System.out.println(list); //降序排序
Collections.sort(list,Collections.reverseOrder()); System.out.print("排序后:");
System.out.println(list);
} }

  程序结果如下:

 
对点进行降序排序

  现在对sort方法进行小结:

  实现了Comparable接口的类都可以用sort方法进行排序,默认的排序方法是升序;如果想进行降序排序,只需把Collections.reverseOrder作为第二个参数传给sort方法。

了解Comparator接口

  上面反复提到的Collections.reverseOrder方法返回的是一个Comparator对象。其实Comparator接口并不陌生,常用的equals方法就来自这个接口。Comparator接口用来定义两个对象之间的比较方法,它有一个叫做compare的方法,函数签名如下:

int compare(T o1,T o2)

   o1 > o2,返回正数;o1 = o2,返回0;o1 < o2,返回负数。
  从前面的例子可以看出,可以使用Comparator对象来控制sort的排序方法,这是如何实现的?查看sort方法的相关源码,我发现其中有这样一段代码:

 
sort方法的相关源码

  注意看图中用红线框起来的部分。经分析可知,这段代码实现了这样的逻辑:如果compare的返回值为正数,就交换进行比较的两个元素的位置。于是可以得出这样一个结论,如果让 x > y 时compare(x,y)返回正数,那么交换 x 和 y 的位置后大的元素在后,这就实现了升序排序;反之,如果让 x < y 时compare(x,y)返回正数,那么交换位置后小的元素在后,这就实现了降序排序。这就是Comparator对象控制排序方式的原理。

 
Comparator对象控制排序方式的原理

  通过Comparator对象来实现点对象的降序排序,一种可行的实现方式如下:

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List; //点类
class Point { private int x;
private int y; public Point(int x,int y)
{
this.x = x;
this.y = y;
} public int getX() {
return x;
} public int getY() {
return y;
} @Override
public String toString() {
return "(" + x + ","+ y + ")";
}
} public class SortDemo { private static List<Point> list = new ArrayList<>(); public static void main(String[] args) { //随机生成10个点
for(int i = 0; i < 10; i++)
{
//点的坐标取值在[1,20]之间
int x = (int)(Math.random() * 20) + 1;
int y = (int)(Math.random() * 20) + 1; list.add(new Point(x,y));
}
System.out.print("排序前:");
System.out.println(list); //降序排序
Collections.sort(list,new Comparator<Point>() { @Override
//当 o1 < o2 时返回正数
public int compare(Point o1, Point o2) {
int distance1 = (o1.getX()) * (o1.getX()) + (o1.getY()) * (o1.getY());
int distance2 = (o2.getX()) * (o2.getX()) + (o2.getY()) * (o2.getY()); return (distance1 < distance2) ? 1 : ((distance1 == distance2) ? 0 : -1);
} }); System.out.print("排序后:");
System.out.println(list);
} }

  程序运行结果如下:

 
通过实现Comparator接口来进行降序排序

  注意,在上面的程序中Point类并没有实现Comparable接口,这是因为已经通过实现Comparator接口来定义Point对象的比较方法,所以也就无需实现Comparable接口。

作者:临江听雨客
链接:https://www.jianshu.com/p/32f9578b9acc
來源:简书
简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

转:浅析Collections.sort的更多相关文章

  1. 泛型的排序问题(Collections.sort及Comparable的应用)

    一.前言    java中对泛型(集合类型)排序的问题,主要采用了两张方式一种是对要排序的实体类,实现Comparable接口,另一种方式,Collections集合工具类进行排序. 二.实现Comp ...

  2. Java Collections.sort方法对list集合排序

    1.排序测试类 package com.ljq.test; import java.util.ArrayList; import java.util.Collections; import java. ...

  3. list集合的排序Comparator和Collections.sort

    一个例子 package sortt; import java.util.ArrayList; import java.util.Collections; import java.util.Compa ...

  4. java中Collections.sort排序详解

    Comparator是个接口,可重写compare()及equals()这两个方法,用于比价功能:如果是null的话,就是使用元素的默认顺序,如a,b,c,d,e,f,g,就是a,b,c,d,e,f, ...

  5. java Collections.sort()实现List排序自定义方法

    方法一: package testSimple; import java.util.ArrayList; import java.util.Collections; import java.util. ...

  6. Java面试总结系列之Collections.sort()

    面试中被问到,集合类中的排序方法是怎么实现的?没有回答上来,故而总结如下:你知道么? 前提:在eclipse中对于自己的代码可以通过按住Ctrl的同时单击名称跳入相应源码中.但eclipse默认没有添 ...

  7. python 中的sort 和java中的Collections.sort()函数的使用

    x=[1,2,3] x.sort()对的,x这个都变了 y=x.sort()错误 y=sorted(x)对的,x拍好序的一个副本 python中用匿名函数和自定义函数排序:(很奇怪的是比较函数返回的是 ...

  8. Java中使用Collections.sort()方法对数字和字符串泛型的LIst进行排序

    在List的排序中常用的是Collections.sort()方法,可以对String类型和Integer类型泛型的List集合进行排序. 首先演示sort()方法对Integer类型泛型的List排 ...

  9. Collections.sort的三种用法

    /** * @author guwh * @version 创建时间:2011-11-3 上午10:49:36 * 类说明 */ package com.jabberchina.test; impor ...

随机推荐

  1. 使用 Dom4j 将 XML 转换为 MAP

    本文为转载:http://blog.sina.com.cn/s/blog_6145ed810100z164.html  原文地址. 自己仅作备忘录方便查找留了一份. 这是解析Xml 的辅助类 pack ...

  2. How to check if Visual Studio 2005 SP1 is installed

    How to check if Visual Studio 2005 SP1 is installed Check the following registry key. HKEY_LOCAL_MAC ...

  3. 设计模式之第14章-命令模式(Java实现)

    设计模式之第14章-命令模式(Java实现) “小明,滚出去.”“小明,这个问题怎么做?”(可怜的小明无奈躺枪.小明:老师,我和你有什么仇什么怨,我和你有什么仇什么怨啊到底...老师:小明,滚出去.习 ...

  4. 56、使用android studio(v1.3.*)修改包名 (rename package name)

    一.修改包名 ①选中目录,开始构造 在弹窗中选中Rename directory 在弹窗中选中Rename package 填写新的包名,点击Refactor 如果有警告,不用管它,直接点击Do Re ...

  5. HTTP-响应状态

    响应状态 有多种响应状态,如:200代表成功,301跳转,404找不到页面,502服务器错误 1xx消息 —— 请求已被服务器接收,继续处理 2xx成功 —— 请求已成功被服务器接收.理解.并接受 3 ...

  6. RHCE认证经典考题

    1:按要求创建用户组及多个用户,设置用户的候选组,设置用户的默认shell. 创建组adminuser. 创建用户natasha和harry属于该组(该组为他们的第二个组). 创建用户sarah,不属 ...

  7. hnust hold不住的老师

    问题 H: Hold不住的老师 时间限制: 1 Sec  内存限制: 128 MB提交: 415  解决: 63[提交][状态][讨论版] 题目描述 因为我们学校ACM集训队取得的一个个优异成绩,AC ...

  8. Leetcode 617.合并二叉树

    合并二叉树 给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠. 你需要将他们合并为一个新的二叉树.合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新 ...

  9. [oldboy-django][2深入django]xss攻击 + csrf

    1 xss攻击 xss攻击(跨站脚本攻击,用户页面提交数据来盗取cookie) - 慎用safe, 和mark_safe -- 如果要用,必须要过滤 - 定义: 用户提交内容,在页面展示用html显示 ...

  10. 【转】一个java页游服务器框架

    源地址:http://www.cnblogs.com/metoy/p/4305326.html?utm_source=tuicool&utm_medium=referral 一.前言 此游戏服 ...