Java中Comparable与Comparator的原理及使用

在排序任务中,可将其分为自然排序:数值大小、字符Asics码序列的排序;客户化排序:也即通过自定义的序列方式进行排序。

1. 自然排序

在JDK类库中,有一部分类实现了Comparable接口,如Integer Double和String等,如下Integer类实现了Comparable的接口,通过重写compareTo方法定义了排序的规则:

返回值 含义
-1 大于
0 等于
1 小于
    //Integer类中部分源码;实现了Comparable的接口,可以进行自然排序
    public final class Integer extends Number implements Comparable<Integer> {
	    public int compareTo(Integer anotherInteger) {
	        return compare(this.value, anotherInteger.value);
	    }
	    
	    public static int compare(int x, int y) {
	        return (x < y) ? -1 : ((x == y) ? 0 : 1);
	    }
	}

JDK中实现了Comparable接口的类库

类名 排序方式
BigDecimal BigInteger Byte Double Float Integer Long Short 按数字大小排序
Character 按字符的Unicode值的数字大小排序
String 按字符中字符的Unicode值排序

注意:使用自然排序时只能向集合中加入同类型的对象,并且这些对象的类必须实现Comparable接口 。

2. 客户化排序

2.1使用Comparable接口

对自己定义的类,设置规则实现排序。如:对学生信息先按照学号升序,再按照成绩降序排列;
创建学生类:

public class A04_Comparable_Student implements Comparable<A04_Comparable_Student> {
	
	private String name;
	private int id;
	private float score;
	public A04_Comparable_Student(String name, int id, float score) {
		// TODO Auto-generated constructor stub
		this.name = name;
		this.id = id;
		this.score = score;
	}
	/**
	 * @return the id
	 */
	public int getId() {
		return id;
	}

	/**
	 * @param id the id to set
	 */
	public void setId(int id) {
		this.id = id;
	}

	/**
	 * @return the name
	 */
	public String getName() {
		return name;
	}
	
	/**
	 * @return the score
	 */
	public float getScore() {
		return score;
	}

	/**
	 * @param score the score to set
	 */
	public void setScore(float score) {
		this.score = score;
	}

	@Override
	public int compareTo(A04_Comparable_Student stu) {
		// TODO Auto-generated method stub
		if (this.id > stu.id) {
			return 1;
		}else if (this.id < stu.id) {
			return -1;
		}else {
			if (this.score > stu.score) {
				return =1;
			}else if (this.score < stu.score) {
				return 1;
			}else {
				return 0;
			}
		}
	}

	@Override
	public String toString() {
		return "A04_Comparable_Student [name=" + name + ", id=" + id + ", score=" + score + "]";
	}
}

初始化学生类并执行排序:

import java.util.Arrays;

public class A04_Comparable_Caller {
	public static void main(String[] args) {
		A04_Comparable_Student stu[] = {
		         new A04_Comparable_Student("张三",20,100f)
				,new A04_Comparable_Student("李四",29,70f)
				,new A04_Comparable_Student("王五",12,80f)
				,new A04_Comparable_Student("王五",12,113f)
				,new A04_Comparable_Student("李四",29,80f)};
		Arrays.sort(stu);
		for (int i = 0; i < stu.length; i++) {
			System.out.println(stu[i].toString());
		}
	}
}

执行结果:
A04_Comparable_Student [name=王五, id=12, score=113.0]
A04_Comparable_Student [name=王五, id=12, score=80.0]
A04_Comparable_Student [name=张三, id=20, score=100.0]
A04_Comparable_Student [name=李四, id=29, score=80.0]
A04_Comparable_Student [name=李四, id=29, score=70.0]

2.2使用Compartor接口

如果一个类已经开放完成,但是在此类建立的初期并没有实现Comparable接口,无法进行对象排序操作的,所以为了解决这一的问题,Java又定义了另一个比较器的操作接口 Comparator 。
定义Comparator:

import java.util.Comparator;

public class A04_MyComparator implements Comparator<A04_Comparable_Student>{
	@Override
	public int compare(A04_Comparable_Student stu1, A04_Comparable_Student stu2) {
		// TODO Auto-generated method stub
		if (stu2.getId() > stu1.getId()) {
			return 1;
		}else if (stu2.getId() < stu1.getId()) {
			return -1;
		}else {
			if (stu2.getScore()> stu1.getScore()) {
				return -1;
			}else if (stu2.getScore()< stu1.getScore()) {
				return 1;
			}else {
				return 0;
			}
		}
	}
}

使用Comparator:

import java.util.Arrays;

public class A04_MyComparator_Caller {
	public static void main(String[] args) {
		A04_Comparable_Student stu[] = {
		         new A04_Comparable_Student("张三",20,100f)
				,new A04_Comparable_Student("李四",29,70f)
				,new A04_Comparable_Student("王五",12,80f)
				,new A04_Comparable_Student("王五",12,113f)
				,new A04_Comparable_Student("李四",29,80f)};
		Arrays.sort(stu,new A04_MyComparator());
		for (int i = 0; i < stu.length; i++) {
			System.out.println(stu[i].toString());
		}
	}
}

执行结果为:
A04_Comparable_Student [name=李四, id=29, score=70.0]
A04_Comparable_Student [name=李四, id=29, score=80.0]
A04_Comparable_Student [name=张三, id=20, score=100.0]
A04_Comparable_Student [name=王五, id=12, score=80.0]
A04_Comparable_Student [name=王五, id=12, score=113.0]

3. Comparable与Comparator排序的原理

Comparable与Comparator的排序操作就是二叉树排序算法:
二叉树排序的基本原理:使用第一个元素作为根节点,之后如果后面的内容比根节点小,则放在左子树,如果内容比根节点的内容要大,则放在右子树。

//Arrays中Comparable排序的源码
private static void binarySort(Object[] a, int lo, int hi, int start) {
        assert lo <= start && start <= hi;
        if (start == lo)
            start++;
        for ( ; start < hi; start++) {
            Comparable pivot = (Comparable) a[start];
            // Set left (and right) to the index where a[start] (pivot) belongs
            int left = lo;
            int right = start;
            assert left <= right;
            /*
             * Invariants:
             *   pivot >= all in [lo, left).
             *   pivot <  all in [right, start).
             */
            while (left < right) {
                int mid = (left + right) >>> 1;
                if (pivot.compareTo(a[mid]) < 0)
                    right = mid;
                else
                    left = mid + 1;
            }
            assert left == right;
            int n = start - left;  // The number of elements to move
            // Switch is just an optimization for arraycopy in default case
            switch (n) {
                case 2:  a[left + 2] = a[left + 1];
                case 1:  a[left + 1] = a[left];
                         break;
                default: System.arraycopy(a, left, a, left + 1, n);
            }
            a[left] = pivot;
        }
    }

4. Comparable接口和Comparator接口的区别

Comparable & Comparator都是用来实现集合中元素的比较、排序的, Comparator位于包java.util下,是在集合内部定义的方法实现的排序,Comparable位于包java.lang下, 是在集合外部实现的排序。

引用:
https://www.cnblogs.com/z2002m/archive/2011/10/24/2222780.html
https://www.jianshu.com/p/81e5c3e88fc6

你可能感兴趣的:(Java基础)