Java 中的排序

一、Arrays.sort()与Collections.sort()排序

1️⃣Arrays.sort() 可以对数组,字符串等排序:

import java.util.Arrays;
 
public class sort {
  public static void main(String[] args) {
    int[] num = new int[]{3,2,4,1,5};
    Arrays.sort(num);
    for(int i=0;i

2️⃣Collections.sort() 是对 list 集合排序,list 也可以放数字、字符串:

import java.util.ArrayList;
import java.util.Collections;
 
public class sort {
  public static void main(String[] args) {
    ArrayList list  = new ArrayList<>();
    list.add(3);
    list.add(2);
    list.add(1);
    Collections.sort(list);
    System.out.print(list);
  }
}
//[1, 2, 3]

3️⃣一般没有特殊要求时,直接调用(底层默认的升序排列)就可以得到想要的结果。所谓的 sort 方法排序底层都是基于这两种排序,故如果需要设计成所想要的排序就需要了解底层排序原理。对自定义对象数组排序,需要引入“比较器”的概念。Compareable 和 Compartor 接口就是比较器抽象接口,通过实现类重写接口方法来进行对象比较。

二、Compareable 接口分析

1️⃣当使用 sort(Objetc[] a) 来进行对象的自然排序时,该对象必需实现 Compareable 接口,重写 compareableTo 方法,并一般在此方法中定义 3 种返回值(正,零,负)来进行排序标准的确认,一般默认下面值来表示:

  1. return 1 时,按照升序。
  2. return 0 时,原位置不动。
  3. return -1 时,按照降序。

而让对象继成 Compareable 接口的方式,称为内部比较器。

2️⃣应用:让需要进行排序的对象的类实现 Comparable 接口,重写 compareTo(),在其中定义排序规则,那么就可以直接调用 Collections.sort() 来排序对象数组。

@Data
public class Student implements Comparable{
    private int id;
    private int age;
    private int height;
    private String name;
    public Student(int id, String name, int age, int height) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.height = height;
    }
    @Override
    public int compareTo(Object o) {
        Student s = (Student) o;
        if (this.age > s.age) {
            return 1;
        }else if (this.age < s.age) {
            return -1;
        }else {
            if (this.height >= s.height) {
                return 1;
            }else {
                return -1;
            }
        }
    }
}

上面是实现升序排列,如果要实现降序只需要把 1 与 -1 互换位置即可。测试类:

public class Test {
    public static void printData(List list) {
        for (Student student : list) {
            System.out.println("学号:"+student.getId()+"姓名:"+student.getName()+
"年龄"+student.getAge()+"身高:"+student.getHeight());
        }
    }
    public static void main(String[] args) {
        List list = new ArrayList<>();
        list.add(new Student(1, "A", 20, 180));
        list.add(new Student(2, "B", 21, 175));
        list.add(new Student(3, "C", 22, 190));
        list.add(new Student(4, "D", 21, 170));
        list.add(new Student(5, "E", 20, 185));
        System.out.println("before sorted");
        printData(list);
        Collections.sort(list);
        System.out.println("after age and height sorted");
        printData(list);
    }
}

结果:

before sorted
学号:1姓名:A年龄20身高:180
学号:2姓名:B年龄21身高:175
学号:3姓名:C年龄22身高:190
学号:4姓名:D年龄21身高:170
学号:5姓名:E年龄20身高:185
after age and height sorted
学号:1姓名:A年龄20身高:180
学号:5姓名:E年龄20身高:185
学号:4姓名:D年龄21身高:170
学号:2姓名:B年龄21身高:175
学号:3姓名:C年龄22身高:190

三、Compartor 接口分析

1️⃣

①先建一个基本属性类:

@Data
public class Student {
    //创建两个基本属性
    String name="";
    int age=0;
    //重写构造方法用来传递数据
    public Student(String name, int age) {
       super();
       this.name = name;
       this.age = age;
    }
}

创建按照姓名升序排列的实现类 :

import java.util.Comparator;
 //按照名字的升序排列    实现接口       泛型是自定义类,里面有要排序的内容   
public class NameSort implements Comparator{
    @Override         //两个参数是泛型的对象
    public int compare(Student o1, Student o2) {
   //按照姓名的升序排列,前面加个负号就按照降序排列
       return o1.getName().compareTo(o2.getName());
    }
}

②直接定义Java中PriorityQueue优先级队列就是利用这原理

Arrays.sort(num,new Comparator(){
//传进来的数组或是字符串以及集合list
    @Override
    public int compare(String o1,String o2){
        return o1.compareTo(o2);//升
        //return o2.compareTo(o1);//降
    }
});

2️⃣应用:实现比较器接口 Comparator,重写 compare 方法,直接当做参数传进 sort 中。

@Data
public class Student {
    private int id;
    private int age;
    private int height;
    private String name;
    public Student(int id, String name, int age, int height) {
        this.id = id;
        this.name = name;
        this.age = age;
        this.height = height;
    }
}

测试类:

public class Test {
    public static void main(String[] args) {
        List list = new ArrayList<>();
        list.add(new Student(1, "A", 20, 180));
        list.add(new Student(2, "B", 21, 175));
        list.add(new Student(3, "C", 22, 190));
        list.add(new Student(4, "D", 21, 170));
        list.add(new Student(5, "E", 20, 185));
        System.out.println("before sorted");
        printData(list);
        Collections.sort(list, new Comparator() {
            @Override
            public int compare(Student o1, Student o2) {
                if(o1.getAge() >= o2.getAge()) {
                    return 1;
                }
                else {
                    return -1;
                }
            }
        });
        System.out.println("after age sorted");
        printData(list);
        Collections.sort(list, new Comparator() {
            @Override
            public int compare(Student o1, Student o2) {
                if(o1.getAge() > o2.getAge()) {
                    return 1;
                }else if (o1.getAge() < o2.getAge()){
                    return -1;
                }else {
                    if (o1.getHeight() >= o2.getHeight()) {
                        return 1;
                    }else {
                        return -1;
                    }
                }
            }
        });
        System.out.println("after age and height sorted");
        printData(list);
    }
    public static void printData(List list) {
        for (Student student : list) {
            System.out.println("学号:"+student.getId()+"姓名:"+student.getName()+
"年龄"+student.getAge()+"身高:"+student.getHeight());
        }
    }
}

输出结果:

before sorted
学号:1姓名:A年龄20身高:180
学号:2姓名:B年龄21身高:175
学号:3姓名:C年龄22身高:190
学号:4姓名:D年龄21身高:170
学号:5姓名:E年龄20身高:185
after age sorted
学号:1姓名:A年龄20身高:180
学号:5姓名:E年龄20身高:185
学号:2姓名:B年龄21身高:175
学号:4姓名:D年龄21身高:170
学号:3姓名:C年龄22身高:190
after age and height sorted
学号:1姓名:A年龄20身高:180
学号:5姓名:E年龄20身高:185
学号:4姓名:D年龄21身高:170
学号:2姓名:B年龄21身高:175
学号:3姓名:C年龄22身高:190

单从上面的例子可以看出排序是稳定的,查看 Java 的Collections.sort的源代码,确实是基于稳定的归并排序实现的,内部还做了优化,叫TimSort。

3️⃣API排序

public static void main(String[] args) {

    List stuList = new ArrayList<>();
    stuList.add(new Student(1, "A", 20, 180));
    stuList.add(new Student(2, "B", 21, 175));
    stuList.add(new Student(3, "C", 22, 190));
    stuList.add(new Student(4, "D", 21, 170));
    stuList.add(new Student(5, "E", 20, 185));

    System.out.println(stuList);

    System.out.println("-------------先年龄升---后身高升-------------");
    Comparator compareAge = Comparator.comparing(Student::getAge);
    Comparator compareHight = Comparator.comparing(Student::getHeight);
    Collections.sort(stuList, compareAge.thenComparing(compareHight));
    for (Student s : stuList) {
        System.out.println(s.getName() + "," + s.getAge() + "," + s.getHeight());
    }

    System.out.println("-------------先年龄升---后身高降-------------");
    Collections.sort(stuList, compareAge.thenComparing(compareHight.reversed()));
    for (Student s : stuList) {
        System.out.println(s.getName() + "," + s.getAge() + "," + s.getHeight());
    }

    System.out.println("-------------先年龄降---后身高降-------------");
    Collections.sort(stuList, compareAge.reversed().thenComparing(compareHight.reversed()));
    for (Student s : stuList) {
        System.out.println(s.getName() + "," + s.getAge() + "," + s.getHeight());
    }
}

输出结果:

[Student(id=1, age=20, height=180, name=A), Student(id=2, age=21, height=175, name=B), Student(id=3, age=22, height=190, name=C), Student(id=4, age=21, height=170, name=D), Student(id=5, age=20, height=185, name=E)]
-------------先年龄升---后身高升-------------
A,20,180
E,20,185
D,21,170
B,21,175
C,22,190
-------------先年龄升---后身高降-------------
E,20,185
A,20,180
B,21,175
D,21,170
C,22,190
-------------先年龄降---后身高降-------------
C,22,190
B,21,175
D,21,170
E,20,185
A,20,180

Process finished with exit code 0

四、compareTo 源码说明

1️⃣String 比较用 compareTo 方法,针对参与比较的不同的字符,从第一位开始往后比较,然后返回相应的 int 值:

  1. 字符个数相同,返回参与比较的前后两个字符串的 ASSIC 码差值。
  2. 两个字符串首字母不同,则该方法返回首字母的 ASSIC 码差值。
  3. 参与比较的两个字符串如果首字符相同,则比较下一个字符,直到有不同的为止,返回该不同的字符的 ASSIC 码差值。
  4. 两个字符串不一样长,可以参与比较的字符又完全一样,则返回两个字符串的长度差值。
  5. 目前 compareTo 项目中的用途是比较版本号的高低。
private final char value[]; 
public int compareTo(String anotherString) {
     int len1 = value.length;
     int len2 = anotherString.value.length;
     int lim = Math.min(len1, len2);
     char v1[] = value;
     char v2[] = anotherString.value;

     int k = 0;
     while (k < lim) {
         char c1 = v1[k];
         char c2 = v2[k];
         if (c1 != c2) {
             return c1 - c2;
         }
         k++;
     }
     return len1 - len2;
}

2️⃣Java 中的 compareto 方法实例

public static void main(String[] args) {
      //返回参与比较的前后两个字符串的ASSIC码的差值
       String a = "a";//97
       String b = "b";//98
       System.out.println("a.compareTo(b):" + a.compareTo(b));//-1
       System.out.println("b.compareTo(a):" + b.compareTo(a));//1

       String c = "c";
       String c1 = "c";
       System.out.println("c.compareTo(c1):" + c.compareTo(c1));//0

       //两个字符串首字母不同,则该方法返回首字母的ASSIC码的差值
       String d = "abc";
       String e = "bcdfg";
       System.out.println("d.compareTo(e):" + d.compareTo(e));//-1

       //参与比较的两个字符串如果首字符相同,则比较下一个字符,
       //直到有不同的为止,返回该不同的字符的ASSIC码差值
       String g = "abedfg";
       System.out.println("d.compareTo(g):" + d.compareTo(g));//-2
       //两个字符串不一样长,可以参与比较的字符又完全一样,
       //则返回两个字符串的长度差值
       String h = "abcdefg";
       System.out.println("d.compareTo(h):" + d.compareTo(h));//-4
       String i = "ab";
       System.out.println("d.compareTo(i):" + d.compareTo(i));//1
       //目前compareTo项目中的用途是比较版本号的高低
       String num = "1.0.0";
       String val = "1.0.1";
       System.out.println("num.compareTo(val):" + num.compareTo(val));//-1
  }

结果如下:
Java 中的排序_第1张图片

3️⃣面试:

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

public class Solution {
    public String PrintMinNumber(int [] numbers) {
        if(numbers.length==0) {
            return "";
        }
        int len = numbers.length;
        String[] str = new String[len];
        StringBuilder sb = new StringBuilder();
        for(int i=0;i(){
            @Override
            public int compare(String o1,String o2){
                String c1 = o1 + o2;
                String c2 = o2 + o1;
                return c1.compareTo(c2);
            }
        });
        for(int i=0;i

你可能感兴趣的:(Java 中的排序)