zoukankan      html  css  js  c++  java
  • Comparable与Comparator

    • Comparable

      public interface Comparable<T> {
          public int compareTo(T o);
      }
      
    • Comparator

      public interface Comparator<T> {
          int compare(T o1, T o2);
          ...
      }
      
    • 区别与联系
      举栗子:

      • Comparable Demo
        import java.util.*;
        
        public class ComparableDemo {
        
            public static void main(String[] args) {
                List<Person> people=new ArrayList<>();
                people.add(new Person(20,Person.MALE));
                people.add(new Person(22,Person.FEMALE));
                people.add(new Person(21,Person.FEMALE));
                people.add(new Person(24,Person.MALE));
        
                people.sort(null);
        //        Collections.sort(people);
                for (Person person:people) {
                    System.out.println(person);
                }
            }
        
            static class Person
                implements Comparable<Person>
            {
                int age;
                String gender;
                static final String MALE="male";
                static final String FEMALE="female";
                public Person(int age,String gender){
                    this.age=age;
                    this.gender=gender;
                }
        
                @Override
                public String toString() {
                    return "age: "+this.age+", gender: "+this.gender;
                }
        
                @Override
                public int compareTo(Person o) {
                    return this.age-o.age;
                }
            }
        }
        
        • 类可以通过实现Comparable接口来扩展排序功能
        • 实现了Comparable的类可以直接调用list的sort和Collections.sort来实现排序
      • Comparator Demo
        import java.util.*;
        
        public class ComparatorDemo {
        
            public static void main(String[] args) {
                List<Person> people=new ArrayList<>();
                people.add(new Person(20,Person.MALE));
                people.add(new Person(22,Person.FEMALE));
                people.add(new Person(21,Person.FEMALE));
                people.add(new Person(24,Person.MALE));
                Comparator<Person> comparator=new Comparator<Person>() {
                    @Override
                    public int compare(Person o1, Person o2) {
                        if (o1==null||o2==null)
                            return 0;
                        return o1.age-o2.age;
                    }
                };
        
                people.sort(comparator);
        //        Collections.sort(people,comparator);
        
                for (Person person:
                 people) {
                    System.out.println(person);
                }
            }
        
            static class Person {
                int age;
                String gender;
                static final String MALE="male";
                static final String FEMALE="female";
                public Person(int age,String gender){
                    this.age=age;
                    this.gender=gender;
                }
        
                @Override
                public String toString() {
                    return "age: "+this.age+", gender: "+this.gender;
                }
            }
        }
        
        • 创建一个实现了Comparator的比较器,也可以在无法扩展bean类的时候达到排序的效果
        • Comparator和Comparable的区别就在于Comparable是由自身来实现list排序的逻辑和功能,Compartor则是通过外部来实现list排序的逻辑和功能
      • 从源代码层面来解析两者的区别:
        • Compartor:

          //先从开始调用的地方开始看:
          Collections.sort(people);
          

          转到Collections的sort源码:

          //Collections.java
          public static <T extends Comparable<? super T>> void sort(List<T> list) {
              list.sort(null);
          }
          

          这里就能看到,其实Collections也是调用了list的sort方法:

          //List.java
          default void sort(Comparator<? super E> c) {
          Object[] a = this.toArray();
          Arrays.sort(a, (Comparator) c);
          ListIterator<E> i = this.listIterator();
          for (Object e : a) {
              i.next();
              i.set((E) e);
          }
          }
          

          从第二行可以看到,调用了Arrays的sort方法

          //Arrays.java
          public static <T> void sort(T[] a, Comparator<? super T> c) {
              if (c == null) {
                  sort(a);
              } else {
                  if (LegacyMergeSort.userRequested)
                      legacyMergeSort(a, c);
                  else
                      TimSort.sort(a, 0, a.length, c, null, 0, 0);
              }
          }
          
          public static void sort(Object[] a) {
              if (LegacyMergeSort.userRequested)
                  legacyMergeSort(a);
              else
                  ComparableTimSort.sort(a, 0, a.length, null, 0, 0);
          }
          
              ...
          
          /** To be removed in a future release. */
          private static void legacyMergeSort(Object[] a) {
              Object[] aux = a.clone();
              mergeSort(aux, a, 0, a.length, 0);
          }
          
          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;
              }
          
              ....
          
              // 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++];
              }
          }
          

          从Arrays的sort方法开始,由于Compartor为null,调用只有一个参数Object[] a的sort函数,然后根据预设好的系统参数:LegacyMergeSort.userRequested来判断调用旧的归并排序函数还是调用一个更高性能的归并排序算法TimSort,这里只对legacyMergeSort进行分析,因为对于Comparable的调用过程来说基本一致,legacyMergeSort会调用mergeSort函数,在mergeSort函数中可以看到:

                  ...
          
                  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);
                  ...
          
          

          会调用实现了Comparable接口的bean类的compareTo方法,因此如果没有实现Comparable接口的类调用sort(null)函数会抛出错误

        • Comparator:代码基本差不多,在Arrays的sort方法,由于Compartor不为null,根据预设好的系统参数:LegacyMergeSort.userRequested来判断调用旧的归并排序函数还是调用一个更高性能的归并排序算法TimSort,以legacyMergeSort为入口:

          private static <T> void legacyMergeSort(T[] a, int fromIndex, int toIndex,
                                              Comparator<? super T> c) {
              T[] aux = copyOfRange(a, fromIndex, toIndex);
              if (c==null)
                  mergeSort(aux, a, fromIndex, toIndex, -fromIndex);
              else
                  mergeSort(aux, a, fromIndex, toIndex, -fromIndex, c);
          }
          
          @SuppressWarnings({"rawtypes", "unchecked"})
          private static void mergeSort(Object[] src,
                                      Object[] dest,
                                      int low, int high, int off,
                                      Comparator c) {
              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 && c.compare(dest[j-1], 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, c);
              mergeSort(dest, src, mid, high, -off, c);
          
              // 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 (c.compare(src[mid-1], 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 && c.compare(src[p], src[q]) <= 0)
                      dest[i] = src[p++];
                  else
                      dest[i] = src[q++];
              }
          }
          

          从带有Comparator参数的mergeSort函数可知:

                  ...
              for (int i=low; i<high; i++)
                      for (int j=i; j>low && c.compare(dest[j-1], dest[j])>0; j--)
                          swap(dest, j, j-1);
                  return;
                  ...
          

          调用了Comparator的compare函数来比较两个bean类

  • 相关阅读:
    linux之awk命令
    HDU 2097 Sky数 进制转换
    HDU 2077 汉诺塔IV
    HDU 2094 产生冠军 dfs加map容器
    HDU 2073 叠框
    HDU 2083 简易版之最短距离
    HDU 2063 过山车 二分匹配
    天梯 1014 装箱问题
    天梯 1214 线段覆盖
    天梯 1098 均分纸牌
  • 原文地址:https://www.cnblogs.com/libertycode/p/9906581.html
Copyright © 2011-2022 走看看