这里所说到的Java中的排序并不是指插入排序、希尔排序、归并排序等具体的排序算法。而是指执行这些排序算法时,比较两个对象“大小”的比较操作。

为了解决如何比较两个对象大小的问题,JDK提供了两个接口 java.lang.Comparablejava.util.Comparator

一、自然排序:java.lang.Comparable

Comparable接口强行对实现它的每个类的对象进行整体排序。这种排序被称为类的自然排序,类的 compareTo(T t) 方法被称为它的自然比较方法

/*Comparable接口中只提供了一个方法:compareTo(Object obj), 该方法的返回值是int。
如果返回值为正数,则表示当前对象(调用该方法的对象)比obj对象“大”;反之“小”;为零
则表示两对象相等。示例如下:*/

public class Stu implements Comparable {
	private int id;
    private String name;
    public Stu() {
    	super();
    }
    @Override
    public int compareTo(Obj obj) {
    	if (obj instanceof Stu) {
        	Stu stu = (Stu) obj;
            return id - stu.id;
        }
        return 0;
    }
}

实现Comparable接口的对象列表(和数组)可以通过 Collections.sort(和 Arrays.sort)进行自动排序。实现此接口的对象可以用作有序映射中的键或有序集合中的元素,无需指定比较器。

二、定制排序:java.util.Comparator

强行对某个对象 collection 进行整体排序 的比较函数。可以将 Comparator 传递给 sort 方法(如 Collections.sort 或 Arrays.sort),从而允许在排序顺序上实现精确控制。还可以使用 Comparator 来控制某些数据结构(如有序 set或有序映射)的顺序,或者为那些没有自然顺序的对象 collection 提供排序。

/**
 *以两段优先队列的代码进行示例:
 *优先队列升序降序:
 */
PriorityQueue<Integer> queueUp = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                //升序   o1 - o2 为正数时候,表示需要调整次序
                return o1 - o2;
            }
        });
        PriorityQueue<Integer> queueDown = new PriorityQueue<>(new Comparator<Integer>() {
            @Override
            public int compare(Integer o1, Integer o2) {
                //降序
                return o2 - o1;
            }
        });
/**
 *以两段优先队列的代码进行示例:
 *优先队列的典例!
 *leetCode1405. 最长快乐字符串
 *代码来自三叶大佬。
 */
public String longestDiverseString(int a, int b, int c) {
		//lambda表达式简写。
        //如果y[1] - x[1] > 0, 则表示需要调整次序,即 x,y 顺序变为 y,x 顺序
        //如果y[1] - x[1] < 0, 则表示无需调整次序,即 x,y 顺序保留;
        //所以队列将,按照PriorityQueue<int[]> q 里的每个 int[] each 的 each[1]
        //进行降序排列。
        PriorityQueue<int[]> q = new PriorityQueue<>((x, y) ->y[1] - x[1]);
        if (a > 0) q.add(new int[]{0, a});
        if (b > 0) q.add(new int[]{1, b});
        if (c > 0) q.add(new int[]{2, c});
        StringBuilder sb = new StringBuilder();
        while (!q.isEmpty()) {
            //每次取出堆顶元素(剩余数量最多的字符)
            int[] cur = q.poll();
            int n = sb.length();
            if (n >= 2 && sb.charAt(n - 1) - 'a' == cur[0] && sb.charAt(n - 2) - 'a' == cur[0]) {
                if (q.isEmpty()) break;
                //取出数量次最多的字符
                int next[] = q.poll();
                sb.append((char)(next[0] + 'a'));
                if (--next[1] != 0) q.add(next);
                q.add(cur);
            } else {
                sb.append((char) (cur[0] + 'a'));
                if (--cur[1] != 0) q.add(cur);
            }
        }
        return sb.toString();
    }
    //优先队列只是保证了每次出队的是最大或者最小的,并不是在队列内部完全排序完成再出队。

三、自然排序和定制排序对比

		//自然排序和定制排序的核心代码:
        //Ⅰ
		public int compareTo(Obj obj) {
        	if (obj instanceof Stu) {
            	Stu stu = (Stu) obj;
                return id - stu.id;
            }
            return 0;
        }
        //Ⅱ
		public int compare(Integer o1, Integer o2) {
                //升序   o1 - o2 为正数时候,表示需要调整次序
                return o1 - o2;
        }
  1. 自然排序于某个类的内部写定,是的这一整个类型的所有对象都可以(默认)按照这个规则来比较大小;而定制排序则是在某次比较中声明的函数,其优先级高于自然排序
  2. 两者的核心代码如上,都遵循这样的规则:返回值为正数,则需要调整次序返回这为负数,则无需调整次序返回值为0表示两者相等。上述代码中,Ⅱ部分,默认顺序为o1, o2; Ⅰ部分, 默认顺序为this(调用者), obj。
  3. 当元素的类型没有实现java.lang.Comparable接口而又不方便修改代码,或者实现了java.lang.Comparable接口的排序规则不适合当前的操作,那么可以考虑使用 Comparator 的对象来排序。