使用lambda表达式实现sort的自定义排序
同步发表于:octal的小站
使用lambda表达式实现sort的自定义排序(C++ and Java)
首先大致讲一下什么是lambda表达式
你也可以将它就当做是匿名函数,lambda表达式其实就是匿名函数演化出的一种语法系统
举个栗子:
普通函数
int function(int x, int y); //声明(定义)
function(1, 2); //调用
匿名函数(lambda表达式)
[](int x, int y){函数主体}; //声明(定义)
[](int x, int y){函数主体}(1, 2); //调用
一个很明显的区别就是使用lambda表达式就省去了给函数命名的工作
而且对于一些简短的函数,直接用lambda表达式声明+调用能提高一点编码效率
就比如说,常用的自定义sort的比较函数
关于lambda表达式如果想进一步了解:
使用Java的同学可以再读读廖老师这篇教程 -> 传送门
使用C++的同学可以读读这篇博客 -> 传送门
如果我们用普通函数的写法来重载运算符
那么是这样写
(想了解更多,可以读读我的这篇文章 -> 传送门)
正文开始
C++篇
#include<bits/stdc++.h>
using namespace std;
int a[15]={0,10,9,8,1,5,2,3,6,4,7};
bool cmp(int x,int y){return x>y;}
//这样实现的是降序
//C++内部默认用的是<实现sort,所以是升序
//比较函数的意义就在于将<重载为>
int main()
{
sort(a, a+11, cmp);
for(int i=0;i<=10;i++)
cout<<a[i]<<" ";
return 0;
}
而用lambda表达式就可以这样写
#include<bits/stdc++.h>
using namespace std;
int a[15]={0,10,9,8,1,5,2,3,6,4,7};
int main()
{
sort(a,a+11,[](int x,int y){return x>y;});
for(int i=0;i<=10;i++)
cout<<a[i]<<" ";
return 0;
}
同样lambda表达式对vector也是适用的
#include<bits/stdc++.h>
using namespace std;
int a[15]={0,10,9,8,1,5,2,3,6,4,7};
int main()
{
vector<int> b;
for(auto x : a) //把a数组复制给b向量
b.push_back(x);
sort(b.begin(),b.end(),[](int x,int y){return x>y;} );
for(int i=0;i<=10;i++)
cout<<b[i]<<" ";
return 0;
}
大多数情况下,我们可能是针对pair或结构体来自定义比较函数
那么修改对应数据类型(结构体名)就ok了,类似这样:
#include<bits/stdc++.h>
using namespace std;
int a[15]={0,10,9,8,1,5,2,3,6,4,7};
typedef pair<int, int> pii;
int main()
{
vector<pii> b;
for(auto x : a) //把a数组复制给b向量
b.push_back(make_pair(x,x+1));
sort(b.begin(),b.end(),[](pii x,pii y){return x.first>y.first;} );
for(int i=0;i<=10;i++)
cout<<b[i].second<<" ";
return 0;
}
补充一点
sort(b.begin(),b.end(),[](int x,int y){return x>y;} );
原本应该是这样的,
sort(b.begin(),b.end(),[](int x,int y) -> bool {return x>y;} );
不过C++可以自动识别函数返回值得数据类型,所以可以简写。
Java篇
//实现对a数组的降序排序
import java.util.*;
public class Main
{
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
Integer[] a = {0,10,9,8,1,5,2,3,6,4,7};
Arrays.sort(a, (x,y) -> {
return y-x;//此处实现的是降序
});
for (int i = 0; i < a.length; i++)
{
System.out.printf("%d ",a[i]);
}
}
}
Java的sort比较机制不同与C++
如果要实现降序就是后-前
升序就是前-后
此外,这样写也能实现降序(用内置compareTo函数)
Arrays.sort(a, (x,y) -> {
return y.compareTo(x);//此处实现的是降序
});
反之,return x.compareTo(y); 就是升序
因为只有一行语句,所以可以更简洁美观一点,直接省略花括号
Arrays.sort(a, (x,y) -> y-x;);
结构体方面,感觉java用起来没有C++舒服
我们就通过这道经典的[NOIP2007 普及组] 奖学金演示一遍Java的写法吧
做这道题需要用到Java的类与接口
朴素做法就是通过自定义一个class从而自定义compareTo来做
import java.util.*;
public class Main
{
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
Student[] stu = new Student[n+5];
for(int i=1; i<=n; i++)
{
int c = sc.nextInt();
int m = sc.nextInt();
int e = sc.nextInt();
stu[i] = new Student(i, c, m, e, c+m+e);
}
Arrays.sort(stu, 1, n+1);
for(int i=1; i<=5; i++)
System.out.println(stu[i].id+" "+stu[i].tot);
}
}
class Student implements Comparable<Student>
{
int c,m,e,id;//语数英、学号
int tot;//总分
public Student(int id,int c,int m,int e,int tot)
{
this.id=id;
this.c=c;
this.m=m;
this.e=e;
this.tot=tot;
}
public int compareTo(Student st)
{
if(this.tot != st.tot) return st.tot-this.tot;
//因为是降序,所以是To后的那个数减前面的数
if(this.c != st.c) return st.c-this.c;
return this.id-st.id;//此处是升序
}
}
不过Java和C++的一个不同点是,
Java没有结构体
而Java里定义一个类本身也就要求必须有compareTo
所以在本题中的这个Student类就没法自定义匿名比较函数
当然这道题想用lambda表达式来简化代码,也是可以的
因为Java里的数组也是对象,所以我们也可以对一个二维数组中进行sort
而lambda表达式也是可以针对数组对象的
import java.util.*;
public class Main
{
public static void main(String[] args)
{
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int[][] a = new int[n+5][6];
for(int i=1; i<=n; i++)
{
a[i][1] = i;
for(int j=2; j<=4; j++)
{
a[i][j] = sc.nextInt();
a[i][5] += a[i][j];
}
}
Arrays.sort(a, 1, 1+n, (x,y)->{
if(x[5] != y[5]) return y[5]-x[5];
if(x[2] != y[2]) return y[2]-x[2];
return x[1]-y[1];
});
for(int i=1; i<=5; i++)
System.out.println(a[i][1]+" "+a[i][5]);
}
}