C++多级排序(比较器应用)

一、介绍

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);
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值