如何使用 std::sort 按特定顺序对字符串进行排序

how to use std::sort to sort strings in a particular order

本文关键字:字符串 定顺序 排序 何使用 std sort      更新时间:2023-10-16

我在我的一个项目中遇到了这种情况,我需要根据给定字符的顺序对字符串进行排序。

所以理想情况下,这是我的要求。

假设我的初始字母顺序是b,B,A,a,d,c,C,D,T,t。

我有 3 根字符串"Bat""bat""atb"。排序后,数组应根据上述给定顺序"bat""Bat""atb" b < B < a

所以我正在考虑使用std::sort的 c++。

但我不确定这整个想法。如果想法很好,可以使用什么数据结构来存储字母的初始顺序以及如何编写排序的比较函数。

sort(arr, arr + 3, compare);
bool compare(string a, string b)
{
    /*how to proceed here?
}

有没有其他方法可以比使用std::sort更有效?

任何想法都会有所帮助。

自定义比较器和std::sort应该足以满足您的操作。比较器的重要部分是确保它遵循严格的弱排序。该排序的属性之一是:

给定 a 和 b,

如果 (!(a < b || b < a)) 为真,则 ab 必须是等价的。

将自定义比较器构造为函子非常简单,是存储字母表的好地方。为了避免即使具有排序logN效率的字符串扫描,也可以使用包含数字排序顺序等价的自定义字母表。这将非常快,对于大型字符串比较尤其出色,因为每个字符查找都是恒定时间。

自定义比较器示例如下:

#include <iostream>
#include <algorithm>
#include <string>
#include <climits>
struct CustomAlphaCmp
{
    int table[1 << CHAR_BIT];
    CustomAlphaCmp(const std::string& alpha)
    {
        std::fill(std::begin(table), std::end(table), INT_MAX);
        int value = 0;
        for (auto x : alpha)
            table[ static_cast<unsigned char>(x) ] = ++value;
    }
    bool operator()(const std::string& a, const std::string& b)
    {
        auto lhs = a.begin();
        auto rhs = b.begin();
        for (; lhs != a.end() && rhs != b.end(); ++lhs,++rhs)
        {
            int lhs_val = table[static_cast<unsigned char>(*lhs)];
            int rhs_val = table[static_cast<unsigned char>(*rhs)];
            if (lhs_val != rhs_val)
                return lhs_val < rhs_val;
        }
        return (rhs != b.end());
    }
};
int main()
{
    std::string alpha = "bBAadcCDTt";
    std::string ar[] = { "Bat", "bat", "X", "atb", "bBb", "bbb", "B",
                         "bat", "aaa", "Y", "Cat", "CaT", "Bat", "A" };
    std::sort(std::begin(ar), std::end(ar), CustomAlphaCmp(alpha));
    for (auto const& s : ar)
        std::cout << s << 'n';
}

输出

bbb
bBb
bat
bat
B
Bat
Bat
A
aaa
atb
CaT
Cat
Y
X

工作原理

比较器对象是从自定义字母表构造的,以使用字母表位置作为表中的"值"来初始化所有可能的char值的表索引。所有非字母字符的值都为 INT_MAX,为它们提供"最弱"的可能顺序值,并将它们全部视为等效。

完成后,比较器将移交给排序算法。比较两个字符串时,将遍历它们,直到遇到不匹配的值或一个/两个字符串达到终止。此时,要么字符串同时完成,要么左边"完成",要么右边先完成。我们知道到目前为止的所有字符都是平等的。因此,如果左边于右边完成,那么只有这样,左边才真正"小于"右边。如果它们是相同的,或者右侧首先完成(不是哪个重要),则左侧不能少。因此,我们可以简单地返回右侧是否到达其终点作为最终答案。

此特定比较器忽略所有非字母字符,因此任何字母字符

都将小于任何非字母字符,并且所有非字母字符都被视为相等。如果这还不足以满足您的需求,则可能需要进行一些调整。

最后,比较器的准备时间是固定的填充成本加上字母长度的O(n)。如果您在许多排序操作中使用相同的字母表,请提前准备比较器并将其发送到std::sort可能是必要的。同样,可能需要根据您的需要进行一些调整。

无论如何,祝你好运。

这是一种自定义排序比较运算符的方法

struct comparisonFuction
{
    inline bool operator() (const YourCustomClass& obj1, const YourCustomClass& obj2)
    {
        return (obj1.customValue < obj2.customValue);
    }
};
std::vector < YourCustomClass > vec;
std::sort(vec.begin(), vec.end(), comparisonFuction());