sort()函数比较器写法及其注意事项,以力扣1005为例

c++标准库算法sort()——参考C++primer p344

sorts算法默认使用元素类型的 < 运算符,但是我们希望的排序顺序可能不是<,或者我们的待排序序列是没有定义<运算符的元素类型(尤其是自定义类型)

所以我们需要sort的第二个版本,此版本是重载过的,接受第三个参数:sort(起始地址,结束地址,比较器),就是传入比较函数的函数名

这样sort就会按照我们自己定义的排序规则来排序了。

示例:

//比较器最好写成static函数,比较器的返回值都是bool类型,为true就说明当前两个元素是<关系,如果为false,s就得交换两个元素
//这里传入的string对象不一定是全局的,树上的例子,可能会写成全局函数,所以就不声明为static了
bool isShorter(const string &s1, const string &s2){
    return s1.size() < s2.size();//也可以是 > 号
}
string s;
sort(s.begin(), s.end(), siShorter);//传入函数名(函数名单独使用就是函数地址,即函数指针)

当然sort还有不需要自己手动写的比较器

less<数据类型>()//从小到大排序
greater<数据类型>()//从大到小排序

    //调用如下
sort(arr,arr+10,less<int>());

比较器的其它要求

1.一般比较器的形参用引用形式,可以节省空间开销
2.sort中的比较函数compare要声明为静态成员函数或全局函数,不能作为普通成员函数,否则会报错。

因为:非静态成员(non-static)函数是依赖于具体对象的,而std::sort这类函数是全局的,如果比较函数cmp是非静态的成员函数,sort中就无法调用非静态成员函数cmp(得创建对象)。静态成员函数或者全局函数是不依赖于具体对象的,
可以独立访问,无须创建任何对象实例就可以访问。

类外函数调用类的static成员函数不用实例化对象但是得加上作用域:func(){A::
cmp();},因为本题sort()是在类内调用cmp,所以不用加作用域

同时注意写cmp时,静态成员函数不可以访问类的非静态成员。

所以我们在比较函数里不能访问对象的普通成员属性,只能访问全局变量或者类的static属性,或者新建临时变量(本题的cmp的形参就是int
&a, int &b)

一般来说就把cmp声明为main函数外面的全局函数,在力扣中就声明为static,毕竟不用自己写main。

示例:
力扣1005. K次取反后最大化的数组和
一开始我的思路是:把元素从小到大排个序[-5, -3, -1, 1, 2, 6]这种,然后从左到右取反,直到k次。乍一看,先把负数取反,然后所有负数用完了再把最小正数取反,好像一定能得到最大和。但是有两个问题:

1,如果k比元素个数还大呢

2,负数取反后绝对值可能比正数小,而取反次数又没用完的情况,比如[ -1, 2, 5 ],k = 3,那肯定不能按前面说的依次从左到右,而是把-1取反三次,或者-1取反1此,2取反两次(当所有数都为正,且剩余的取反次数为偶数时,那对谁反复取反都一样,反正结果是正数)

怎样才能在k还有剩余时找到那个正数呢,重新排序?

代码随想录里做这题没有重新排序,而是把数组按照绝对值大小排序,从高到低排(从低到高也可以,就是for遍历顺序不一样)

1.先把绝对值大,且为负数的取反

2.k要是还有剩余,如果剩余次数是偶数的话,那就不用管了,都是正数了随便找一个取反偶数次也是整数;如果是奇数,那就对最小正数取反,因为是按绝对值排的序,那最右边上那个就是最小正数

完整代码:

class Solution {
private:
    //声明为static
    static bool cmp(int& a, int& b){
        return abs(a) > abs(b);//绝对值降序排列
    }

public:
    int largestSumAfterKNegations(vector<int>& nums, int k) {
        sort(nums.begin(), nums.end(), cmp);//绝对值降序排列
        int result  = 0;
        for(int i = 0; i < nums.size(); i++){//i的范围不是 < k,k如果大于nums.size()会越界
            if( k > 0 && nums[i] < 0){
                nums[i] = -nums[i];
                k--;
            }
        }
        //如果剩下的k为奇数
        if(k % 2 == 1) nums[nums.size() - 1] *= -1;//乘以-1即取反
        for(int i : nums){
            result += i;
        }
        return result;
    }
};

补充:
如果是对二维的vector排序呢:
比如力扣406,代码如下

class Solution {
public:
    static bool cmp(const vector<int>& a, const vector<int>& b) {
        if (a[0] == b[0]) return a[1] < b[1];
        return a[0] > b[0];
    }
    vector<vector<int>> reconstructQueue(vector<vector<int>>& people) {
        sort (people.begin(), people.end(), cmp);
       //隐去后面部分
    }
};

比较器cmp其实一直是两个参数,无论对多少维的数组都这样,因为这两参数代表相邻的两个元素。
当他们各自也是数组时,那有时候就需要依次指定后面的比较顺序:
在这里插入图片描述
如果我们按照对上面的二维数组的第一列排序时,那只要比较a[0]和b[0]即可,要是还要按第二列排序,那就需要继续往下指定。

//按照二维数组第一列的大小对每个一维数组升序排序,
//如何第一列相同时,按照第二列大小对每行的数组降序排序
 bool cmp(vector<int>&a,vector<int>&b){
    if(a[0]!=b[0]) return a[0]<b[0];
     else return a[1]>b[1];
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值