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<num.length;i++) {
      System.out.print(num[i]+" ");
    }
  }
}
//1 2 3 4 5

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

import java.util.ArrayList;
import java.util.Collections;
 
public class sort {
  public static void main(String[] args) {
    ArrayList<Integer> 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 接口,重写 compareTo 方法,并一般在此方法中定义 3 种返回值(正,零,负)来进行排序标准的确认,一般默认下面值来表示:

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

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<Student> list) {
		for (Student student : list) {
			System.out.println("学号:"+student.getId()+"姓名:"+student.getName()+
"年龄"+student.getAge()+"身高:"+student.getHeight());
		}
	}
	public static void main(String[] args) {
		List<Student> 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优先级队列就是利用这原理

//传进来的数组或是字符串以及集合list
Arrays.sort(num,new Comparator<String>(){
    @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<Student> 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<Student>() {
			@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<Student>() {
			@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<Student> 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<Student> 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<Student> compareAge = Comparator.comparing(Student::getAge);
    Comparator<Student> 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
  }

结果如下:

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<len;i++) {
            str[i] = String.valueOf(numbers[i]);
        }
        Arrays.sort(str,new Comparator<String>(){
            @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<len;i++) {
            sb.append(str[i]);
        }
        return sb.toString();
    }
}
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JFS_Study

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值