在C++的标准库中,std::sort是一个非常常用的排序函数,它默认按照升序对元素进行排序。但实际开发中我们往往需要实现更复杂的排序逻辑,比如对自定义结构体排序、按照特定规则降序排序或者多条件排序,这时候就需要自定义sort的比较函数。比较函数的核心作用是定义两个元素之间的大小关系,让std::sort能够根据这个关系完成排序。

比较函数的基本规则
自定义的比较函数需要满足严格弱序的要求,简单来说就是对于任意两个元素a和b,比较函数的返回值需要符合以下逻辑:
- 如果a应该排在b前面,返回true
- 如果b应该排在a前面,返回false
- 不能出现a和b互相比较都返回true的情况,否则会导致未定义行为
对于基本数据类型,比如int类型,升序排序的比较函数可以写成:当a小于b时返回true,这样小的元素就会排在前面。
不同方式实现自定义比较函数
方式一:普通函数作为比较函数
我们可以定义一个普通的全局函数或者静态函数作为比较函数,将其作为std::sort的第三个参数传入。
比如实现int数组的降序排序:
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
// 降序比较函数,a大于b时返回true,a会排在b前面
bool descCompare(int a, int b) {
return a > b;
}
int main() {
vector<int> nums = {3, 1, 4, 1, 5, 9};
// 传入自定义的比较函数
sort(nums.begin(), nums.end(), descCompare);
for (int num : nums) {
cout << num << " ";
}
// 输出结果:9 5 4 3 1 1
return 0;
}
方式二:函数对象(仿函数)作为比较函数
函数对象是一个重载了operator()的类实例,它可以保存状态,比普通函数更灵活。
比如实现一个可以指定升序降序的比较函数对象:
#include <algorithm>
#include <vector>
#include <iostream>
using namespace std;
class Compare {
private:
bool isDesc; // 是否降序
public:
Compare(bool desc) : isDesc(desc) {}
// 重载()运算符
bool operator()(int a, int b) const {
if (isDesc) {
return a > b; // 降序
} else {
return a < b; // 升序
}
}
};
int main() {
vector<int> nums = {3, 1, 4, 1, 5, 9};
// 传入函数对象实例,指定降序
sort(nums.begin(), nums.end(), Compare(true));
for (int num : nums) {
cout << num << " ";
}
// 输出结果:9 5 4 3 1 1
return 0;
}
方式三:lambda表达式作为比较函数
lambda表达式是C++11之后引入的特性,适合编写简单的、一次性的比较逻辑,不需要额外定义函数或者类。
比如对自定义结构体按照成员排序:
#include <algorithm>
#include <vector>
#include <iostream>
#include <string>
using namespace std;
// 自定义学生结构体
struct Student {
string name;
int score;
};
int main() {
vector<Student> students = {
{"张三", 85},
{"李四", 92},
{"王五", 78}
};
// lambda表达式作为比较函数,按照分数降序排序
sort(students.begin(), students.end(), [](const Student& a, const Student& b) {
return a.score > b.score;
});
for (const Student& s : students) {
cout << s.name << " " << s.score << endl;
}
// 输出结果:
// 李四 92
// 张三 85
// 王五 78
return 0;
}
多条件排序的实现
当我们需要按照多个条件排序时,比如先按照分数降序,分数相同再按照姓名升序,只需要在比较函数中依次判断条件即可。
#include <algorithm>
#include <vector>
#include <iostream>
#include <string>
using namespace std;
struct Student {
string name;
int score;
};
int main() {
vector<Student> students = {
{"张三", 85},
{"李四", 92},
{"王五", 85},
{"赵六", 78}
};
// 多条件比较:先按分数降序,分数相同按姓名升序
sort(students.begin(), students.end(), [](const Student& a, const Student& b) {
if (a.score != b.score) {
return a.score > b.score; // 分数不同,分数高的在前
} else {
return a.name < b.name; // 分数相同,姓名小的在前
}
});
for (const Student& s : students) {
cout << s.name << " " << s.score << endl;
}
// 输出结果:
// 李四 92
// 王五 85
// 张三 85
// 赵六 78
return 0;
}
常见注意事项
- 比较函数的参数类型需要和容器中的元素类型匹配,最好使用const引用避免不必要的拷贝
- 不要出现比较函数对a和b都返回true的情况,比如写成
return a >= b;就是错误的,会导致排序结果异常 - 如果是对自定义结构体排序,比较函数需要能够访问到结构体的对应成员,或者结构体内部重载了比较运算符
- lambda表达式作为比较函数时,如果逻辑比较复杂,建议单独定义函数,提高代码可读性