起因:
在做leetcode上的题目时经常遇到需要辅助函数的情况,但是leetcode的特殊方式(输入不用自己处理,只需要写算法主体)会导致solve函数中的部分变量不能够实现全局,不方便传入函数。在被大佬的代码教育之后发现了这个写法,分享给你的同时也可以给自己留下备忘录
正文
function 用法大致和c语言中的函数指针类似(指向函数的指针)
补充:c的函数指针
基本语法:与下面的function用法基本相同
返回类型 + (* +指针名) (参量类型) = 函数名 //()括号不可省略
int print(int x){
return x ;
}
int main()
{
int x;
cin >> x;
int (*f) (int) = print ;
cout <<f(x) << endl;
cout <<print(x) <<endl;
return 0;
}
返回指向函数的指针
基本语法:
声明指针类型: using 指针类型 = (返回类型+*)(参数)
#include <bits/stdc++.h>
using namespace std;
using f = int (*)(int , int );//这是一个指向 int (int , int) 型的函数指针类型
int add(int a ,int b ){
return a+b;
}
int sub(int a,int b ){
return a-b;
}
int mul(int a,int b ){
return a*b;
}
int dv(int a , int b){
return a / b;
}
int main()
{
int a ,b;
cin >> a >> b;
f f1 = add;
cout << f1(a,b)<< endl;
vector<f> v {add,sub,mul,dv};//vector 中储存的是指针
for (auto &x : v){
cout << x(a,b)<<endl;//通过指针进行调用
}
return 0;
}
基本语法:
function <返回值 (参量类型)> 变量名(要指向的函数)
用法其一:
#include <bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
using namespace std;
int cnt[26];
void print1(){
cout << "函数1" <<endl;
return ;
}
void print2(){
cout << "函数2" <<endl;
return ;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
function <void ()> f(&print1);
f(); //调用第一个函数
f = &print2;//指向第二个函数
f();
return 0;
}
输出结果:
函数1
函数2
tips:function 类型的变量一旦声明了类型(< > 里面的东西) 就只能指向相同类型函数,不能指向其他类型的
例:
void print1(){
cout << "函数1" <<endl;
return ;
}
void print2(int x){
cout << "函数2" <<endl;
return ;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
function <void ()> f(&print1);
f(); //调用第一个函数
f = &print2;//指向第二个函数
f();
return 0;
}
很明显会报错,因为第二个函数中有变量而我们定义的f没有变量这个类型,所以不匹配
lambada 表达式
一般用于定义匿名函数,使得代码更加灵活简洁。lambda表达式与普通函数类似,也有参数列表、返回值类型和函数体,只是它的定义方式更简洁,并且可以在函数内部定义。
基本语法:
返回类型 函数名(变量名) = [ ] (变量和变量名) -> 返回类型 {函数内容+返回};
例:
auto add = [] (int a ,int b) -> int {cout <<"这是加法"<<endl;return a+b;};
cout << add(1,2)<<endl;
输出结果:
这是加法
3
补充:[ ]内的东西 是 捕获列表,是Lambda表达式是否能够使用外部变量的基础
主要有
[ ] Lambda 表达式不能使用外部任何变量(全局变量除外)
[=] 按赋值的方式捕获变量(无法修改外部变量)
[&] 按引用的方式捕获,传递的是地址,可以修改外部
[=, &a] 除了变量a之外,按值的方式捕获所有局部变量,变量a使用引用的方式来捕获。这里可以按引用捕获多个,例如 [=, &a, &b,&c]。这里注意,如果前面加了=,后面加的具体的参数必须以引用的方式来捕获,否则会报错。
[&, a] 除了变量a之外,按引用的方式捕获所有局部变量,变量a使用值的方式来捕获。这里后面的参数也可以多个,例如 [&, a, b, c]。这里注意,如果前面加了&,后面加的具体的参数必须以值的方式来捕获。
[a, &b] 以值的方式捕获a,引用的方式捕获b,也可以捕获多个
[this] 捕获this指针,在成员函数中,[=]和[&]也会捕获this指针。
重点来了:function + Lambada
function<返回类型(参量类型)> 函数名 = [捕获列表] (参量) {函数体+返回};
或者
function<返回类型(参量类型)> 函数名 = [捕获列表] (参量) -> 返回类型 {函数体+返回};
例:
在为了使用二分查找的过程中简化代码(
懒)我使用了这个方式来写check函数
顺带一提,这个题目是二分答案,还挺新颖的(孩子没见过世面)
AC代码:
class Solution {
public:
int maximumTastiness(vector<int>& p, int k) {
sort(p.begin() , p.end());
int n = p.size();
//二分答案
//所有的结果只能在在0到最后一个数字减去第一个数字之间
//所以二分 0 - x 这个区间即可得到答案
int r = p[n - 1] - p[0] , l = 0;
function <bool(int , int)> check = [&] (int x , int k) {
int cnt = 1;//当前数字已经选择了
for (int i = 0 , j = 1 ; j < n ; j ++){
if (p[j] - p[i] >= x){
cnt ++;
i = j;
}
}
//如果
return cnt >= k;//当选择的答案较小时会导致cnt的数量大于k
};
while(l <= r){//目标是要略大于想要的答案所以要等于
int mid = (l + r) >> 1;
if(check(mid , k)) l = mid+1;
else r = mid -1;
}
return r;
}
};
function哪里也也可以使用Lambda表达式
function <bool(int , int)> check = [&] (int x , int k) ->bool{
int cnt = 1;//当前数字已经选择了
for (int i = 0 , j = 1 ; j < n ; j ++){
if (p[j] - p[i] >= x){
cnt ++;
i = j;
}
}
//如果
return cnt >= k;//当选择的答案较小时会导致cnt的数量大于k
};
其余知识:
- 内联函数,c++ 中每次调用函数都会放入栈中,频繁调用函数会导致堆栈溢出,而内敛函数在调用时会进行代码展开,将所有调用这个函数的调用点都替换为函数的代码,从而避免了堆栈溢出(类内的函数是默认的inline函数)
使用方法:
在函数前面加上inline 即可
一般会放在头文件中进行声明,因为内联函数是可以重复定义的
示例:
#include <bits/stdc++.h>
using namespace std;
inline int print(int x){
return x ;
}
int main()
{
int x ; cin >> x;
cout << print(x) ;//这里会被展开为return x
return 0;
}
写在最后
谢谢观看!!!
这是一系列记录自己成长的文章,如果对你有帮助的话我会很开心的
顺带上次qq机器人的东西还没写呢(恼)
更详细的可以参考这两篇文章:
深入浅出C++的function - 知乎 (zhihu.com)
C++ Lambda表达式的完整介绍 - 知乎 (zhihu.com)
今日你WA了吗
给大佬磕头orz