自定义方法实现理解加算法讲解
各位同学在理解做题或者写程序的时候,如果遇到自定义sort方法时,对于容器的自定义排序或者数组的自定义排序这里通过一道例题进行讲解!!!
AcWing 802. JAVA区间和
某小学最近得到了一笔赞助,打算拿出其中一部分为学习成绩优秀的前5名学生发奖学金。
期末,每个学生都有3门课的成绩:语文、数学、英语。
先按总分从高到低排序,如果两个同学总分相同,再按语文成绩从高到低排序,如果两个同学总分和语文成绩都相同,那么规定学号小的同学排在前面,这样,每个学生的排序是唯一确定的。
任务:先根据输入的3门课的成绩计算总分,然后按上述规则排序,最后按排名顺序输出前五名名学生的学号和总分。
注意,在前5名同学中,每个人的奖学金都不相同,因此,你必须严格按上述规则排序。
例如,在某个正确答案中,如果前两行的输出数据(每行输出两个数:学号、总分) 是:
7 279
5 279
这两行数据的含义是:总分最高的两个同学的学号依次是7号、5号。
这两名同学的总分都是279 (总分等于输入的语文、数学、英语三科成绩之和),但学号为7的学生语文成绩更高一些。
如果你的前两名的输出数据是:
5 279
7 279
则按输出错误处理。
输入格式
输入文件包含n+1行:
第1行为一个正整数n,表示该校参加评选的学生人数。
第2到n+1行,每行有3个用空格隔开的数字,每个数字都在0到100之间,第j行的3个数字依次表示学号为j-1的学生的语文、数学、英语的成绩。
每个学生的学号按照输入顺序编号为1~n (恰好是输入数据的行号减1)。
所给的数据都是正确的,不必检验。
输出格式
输出文件共有5行,每行是两个用空格隔开的正整数,依次表示前5名学生的学号和总分。
数据范围
6≤n≤300
输入样例:
6
90 67 80
87 66 91
78 89 91
88 99 77
67 89 64
78 89 98
输出样例:
6 265
4 264
3 258
2 244
1 237
解法一:冒泡排序+swap
这种解法是我写的一种比较暴力的方法,每次都要交换三个数组中的值,很是繁琐!! 学了后面的自定义就简单多了!!!
class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int sum[] = new int[305];
int c[] = new int[305];
int index[] = new int[305];
for (int i = 1; i <= n; i++) {
index[i] = i;
c[i] = sc.nextInt();
sum[i] = c[i] + sc.nextInt() + sc.nextInt();
}
int temp = 0;
for (int i = 1; i < n; i++) {
for (int j = 1; j < n - i + 1; j++) {
if (sum[j] > sum[j + 1]) {
temp = sum[j];
sum[j] = sum[j + 1];
sum[j + 1] = temp;
temp = c[j];
c[j] = c[j + 1];
c[j + 1] = temp;
temp = index[j];
index[j] = index[j + 1];
index[j + 1] = temp;
}
if (sum[j] == sum[j + 1]) {
if (c[j] > c[j + 1]) {
temp = sum[j];
sum[j] = sum[j + 1];
sum[j + 1] = temp;
temp = c[j];
c[j] = c[j + 1];
c[j + 1] = temp;
temp = index[j];
index[j] = index[j + 1];
index[j + 1] = temp;
}
if (c[j] == c[j + 1]) {
if (index[j] < index[j + 1]) {
temp = sum[j];
sum[j] = sum[j + 1];
sum[j + 1] = temp;
temp = c[j];
c[j] = c[j + 1];
c[j + 1] = temp;
temp = index[j];
index[j] = index[j + 1];
index[j + 1] = temp;
}
}
}
}
}
for (int i = n; i > n - 5; i--) {
System.out.println(index[i] + " " + sum[i]);
}
}
}
解法二:自定义list集合排序方法
集合模板:当然底下的Collections可以换为list等实现类
Collections.sort(new Comparator<类名或者基本类型名>() {
@Override
public int compare(类名或者基本类型名 o1, 类名或者基本类型名 o2) {
return 0;
}
});
现在都是lambda表达式:
Collections.sort((o1, o2) -> {
return o1 - o2;
}
这里的o1和o2的类型是集合中元素的类型。
import java.util.*;
class Main {
static List<Student> list = new ArrayList<>();
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
for (int i = 1; i <= n; i++) {
int c =sc.nextInt();
int m = sc.nextInt();
int e = sc.nextInt();
Student student = new Student(c,m,e,c+m+e,i);
list.add(student);
}
list.sort((a, b) -> {
if (a.total == b.total) {
if (a.chinese == b.chinese) {
return a.id - b.id;
} else {
return b.chinese - a.chinese;
}
} else {
return b.total - a.total;
}
});
for(int i =0;i<5;i++){
System.out.println(list.get(i).id+" "+list.get(i).total);
}
}
}
class Student {
//语文成绩
int chinese;
//数学成绩
int math;
//英语成绩
int english;
//总分
int total;
//学生id
int id;
public Student(int chinese, int math, int english, int total, int id) {
this.id = id;
this.chinese = chinese;
this.math = math;
this.english = english;
this.total = total;
}
}
解法三:自定义Arrays排序方法
Array.sort()方法模板:
Arrays.sort(T[], new Comparator<T>() {
public int compare(T a, T b){
return fa - fb;
}
});
默认为从小到大排序,用参数a减参数b。若需要从大到小排序,则用参数b减参数a。(不一定是相减,从小到大排按正常思路,参数a大则返回正数;若要从大到小排,则按相反思路,参数a大则返回负数)
现在都改用lambda表达式了:
建议用这种:
Arrays.sort(nums, (o1, o2) -> {
return o1 - o2;
}
这里的o1和o2的类型是数组中元素的类型。
import java.util.*;
class Main {
static int n;
static int [][]nums;
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
nums = new int[n][4];
for(int i =0;i<n;i++){
nums[i][0] = sc.nextInt();
nums[i][1] = sc.nextInt();
nums[i][2] = sc.nextInt();
nums[i][3] = i+1;
}
Arrays.sort(nums, (o1, o2) -> {
int s1 = o1[0]+o1[1]+o1[2];
int s2 = o2[0]+o2[1]+o2[2];
if(s1!=s2){
return s2 - s1;
}
if(o1[0]!=o2[0]){
return o2[0]-o1[0];
}
return o1[3] - o2[3];
});
for(int i =0;i<5;i++){
int s[] = nums[i];
System.out.println(s[3]+" "+(s[0]+s[1]+s[2]));
}
}
}