一、介绍
C++的比较器与java类似。首先自己定义比较逻辑(一个函数),然后将比较逻辑传入c++提供的排序方法中,按照比较逻辑进行排序。
二、 一个例子
#include <string>
#include <vector>
#include <iostream>
#include<iomanip>
#include <algorithm>
#include <set>
#include <chrono>
#include <random>
using namespace std;
//排序规则
typedef struct _sortRule {
int col; //字段号
int sortType; //排序方式:0,按字符串排;1,按数字排
int iSAEs; //0,升序;非0,降序
} TSortRule;
//待排序的数据集
typedef struct sortData {
int index; //数据所在的列号
vector<string> data; //数据
vector<TSortRule> sortRules; //排序规则
} SortData;
/*
* 比较器逻辑
* 如果想要升序排序,那么(1<2<3)左边的数据小于右边的。也就是l<r为:true
* 如果想要降序排序,那么(3<2<1)左边的数据大于右边的。也就是l>r为:true
*/
bool cmpLogic(const SortData &l, const SortData &r, int index, int size) {
if (index == size) {
return true;
}
//升序
if (l.sortRules[index].iSAEs == 0) {
//按数字排序
if (l.sortRules[index].sortType == 1) {
// 如果想要升序排序,那么(1<2<3)左边的数据小于右边的。也就是l<r为:true
// 如果想要降序排序,那么(3<2<1)左边的数据大于右边的。也就是l>r为:true
if (strtol(l.data[index].c_str(), nullptr, 10) < strtol(r.data[index].c_str(), nullptr, 10)) {
return true;
}
if (strtol(l.data[index].c_str(), nullptr, 10) > strtol(r.data[index].c_str(), nullptr, 10)) {
return false;
}
if (strtol(l.data[index].c_str(), nullptr, 10) == strtol(r.data[index].c_str(), nullptr, 10)) {
cmpLogic(l, r, index + 1, size);
}
} else { //按字符串排序
if (l.data[index].compare(r.data[index])<0) {
return true;
}
if (l.data[index].compare(r.data[index])>0) {
return false;
}
if (strcmp(l.data[index].data(),r.data[index].data())==0) {
cmpLogic(l, r, index + 1, size);
}
}
} else { //降序
if (l.sortRules[index].sortType == 1) {
if (strtol(l.data[index].c_str(), nullptr, 10) > strtol(r.data[index].c_str(), nullptr, 10)) {
return true;
}
if (strtol(l.data[index].c_str(), nullptr, 10) < strtol(r.data[index].c_str(), nullptr, 10)) {
return false;
}
if (strtol(l.data[index].c_str(), nullptr, 10) == strtol(r.data[index].c_str(), nullptr, 10)) {
cmpLogic(l, r, index + 1, size);
}
} else {
if (l.data[index].compare(r.data[index])>0) {
return true;
}
if (l.data[index].compare(r.data[index])<0) {
return false;
}
if (strcmp(l.data[index].data(),r.data[index].data())==0) {
cmpLogic(l, r, index + 1, size);
}
}
}
}
/*
* 自定义比较器,这个函数就是排序的依据。
* 如果想要升序排序,那么(1<2<3)左边的数据小于右边的。也就是l<r为:true
* 如果想要降序排序,那么(3<2<1)左边的数据大于右边的。也就是l>r为:true
*/
bool cmp(const SortData &l, const SortData &r) {
int minNum = min(l.data.size(), l.sortRules.size());
return cmpLogic(l, r, 0, minNum);
}
/**
* @brief 对二维表进行排序
* @param list,二维vector定义的二维表;
* @param sortRules,排序规则
* @param inrows,参加排序的记录列表
* @param outrows,顺序索引列表(二维表本身并不排序,排序结果由本索引表承担)
* @return 0,成功;恒为0
* @note 本算法要求性能足够高,可支持百万级记录数
*/
int Sort(const vector<vector<string>> &list, const vector<TSortRule> &sortRules, const vector<size_t> &inrows,
vector<size_t> &outrows) {
//初始化待排序的list
vector<SortData> sortList;
for (size_t i: inrows) {
SortData sortData;
sortData.index = i;
sortData.data = list[i];
cout << sortData.index << ":";
for (const string &str: list[i]) {
cout << str << " ";
}
cout << "" << endl;
sortData.sortRules = sortRules;
sortList.emplace_back(sortData);
}
/*
* 核心,调用<algorithm>库提供的排序函数sort(const _RanIt _First(待排序的集合的开始位置), const _RanIt _Last(待排序的集合的开始位置), _Pr _Pred(传入一个函数,也就是比较器))
*/
sort(sortList.begin(), sortList.end(), cmp);
cout << "排序后的序列:" << endl;
for (const SortData &sortData1:sortList) {
outrows.emplace_back(sortData1.index);
cout << sortData1.index << " " << endl;
}
return 0;
}
/**
* 初始化list,大小为40*20,每行,前十个为:数字(随机获取),后十个为:rmb_+随机数
* @param list
* @param rows
*/
void initData(vector<vector<string>> &list, int rows) {
list.resize(rows);
std::random_device rd; //Get a random seed from the OS entropy device, or whatever
std::mt19937_64 eng(rd()); //Use the 64-bit Mersenne Twister 19937 generator
int maxnum = 100;
std::uniform_int_distribution<unsigned long long> distr(8, rows);// distribution in range [1, num]
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 10; j++) {
list[i].emplace_back(to_string(distr(eng)));
}
for (int j = 0; j < 10; j++) {
list[i].emplace_back("rmb_" + to_string(distr(eng)));
}
}
}
class elapsedtimer {
public:
elapsedtimer() : m_begin(std::chrono::high_resolution_clock::Now()) {}
void reset() { m_begin = std::chrono::high_resolution_clock::Now(); }
//ns
int64_t elapsed_ns() const {
return std::chrono::duration_cast<std::chrono::nanoseconds>(
std::chrono::high_resolution_clock::Now() - m_begin).count();
}
//us
int64_t elapsed_us() const {
return std::chrono::duration_cast<std::chrono::microseconds>(
std::chrono::high_resolution_clock::Now() - m_begin).count();
}
//ms
int64_t elapsed_ms() const {
return std::chrono::duration_cast<std::chrono::milliseconds>(
std::chrono::high_resolution_clock::Now() - m_begin).count();
}
//s
int64_t elapsed_s() const {
return std::chrono::duration_cast<std::chrono::seconds>(
std::chrono::high_resolution_clock::Now() - m_begin).count();
}
//m
int64_t elapsed_min() const {
return std::chrono::duration_cast<std::chrono::minutes>(
std::chrono::high_resolution_clock::Now() - m_begin).count();
}
//h
int64_t elapsed_hours() const {
return std::chrono::duration_cast<std::chrono::hours>(
std::chrono::high_resolution_clock::Now() - m_begin).count();
}
private:
std::chrono::time_point<std::chrono::high_resolution_clock> m_begin;
};
void test(int datanum, int col, int sorttype) {
vector<vector<string>> list;
elapsedtimer et;
initData(list, datanum);
cout << "init ms:" << et.elapsed_ms() << endl;
vector<TSortRule> sortRules;
TSortRule sortRule;
for (int i = 0; i < col; i++) {
sortRule.col = i;
if (sorttype > 1) {
sortRule.sortType = (sorttype + i) % 2;
} else {
sortRule.sortType = sorttype;
}
sortRule.iSAEs = 0;
sortRules.emplace_back(sortRule);
}
vector<size_t> outrows;
vector<size_t> inrows = {1, 2, 3, 4};
et.reset();
Sort(list, sortRules, inrows, outrows);
printf("%d\t%d\t%s\tms:%lld\n", datanum, col, sorttype ? "int" : "str", et.elapsed_ms());
// FILE *fp = fopen("./times1.txt", "a+");
// fprintf(fp, "%d\t%d\t%s\t%s\t%lld\n", datanum, col, sorttype > 1 ? "混合" : (sorttype? "整形":"字符串"), altype? "pair" : "list", et.elapsed_ms());
// fflush(fp);
// fclose(fp);
}
int main() {
test(40, 5, 0);
}