使用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]);
    }
}

这样写,代码就简化很多了

posted @ 2023-01-02 22:17  octal_zhihao  阅读(3057)  评论(0编辑  收藏  举报