重用字符串比较的结果以获得更快的std :: sort

时间:2018-01-29 21:35:13

标签: c++ string sorting predicate strcmp

我想用strcmp对唯一字符串的矢量进行排序。

std::sort期望一个谓词告诉一个字符串是否小于另一个字符串,但strcmp实际上已经返回字符串的关系,实际上明智的做法是利用该信息而不是松散它

这很有用,因为它还需要确定字符串是否相等 - 在这种情况下,谓词将使用相同的字符串再次调用,但是以反向参数顺序。

这是一种天真的排序方式:

vector<const char*> cache;
sort(cache.begin(), cache.end(), [](const char* left, const char* right)
{
    return strcmp(left, right) < 0;
});

我正在尝试以下想法,在那里我存储比较结果并重新使用它,如果再次比较相同的字符串。

vector<const char*> cache;
sort(cache.begin(), cache.end(), [notLess = false, r = (const char*)nullptr](const char* left, const char* right) mutable
{
    // possibly reuse previous comparison of same strings passed in inverse order
    if (notLess &&
        r == left)
    {
        notLess = false;
        // always less since vector contains unique strings
        return true;
    }

    if (notLess = strcmp(left, right) >= 0)
        r = right;
    return !notLess;
});

为了限制存储的信息和额外引入的比较的数量,我想到只存储字符串,它正在成为反向比较的左边。

现在,我的实际问题是,仅检查以前的正确的字符串是否足够,还是需要存储并检查以前的字符串?< / p>

2 个答案:

答案 0 :(得分:3)

首先,你的假设是错误的。 std::sort不会两次使用相同的参数调用比较。结果,整个想法都存在缺陷。

第二个(更重要的是)你的想法是有缺陷的,因为谓词不应该保持状态。 std::sort可以复制那些谓词并重用副本(实际上,gcc版本肯定会在我前一段时间检查时复制谓词),从而打破整个比较。

答案 1 :(得分:0)

是的,在这里提出的案例中,这个想法并不有用,因为sort并不需要区分确切的等价 - 它可以轻松地混合a > b和{{1 (感谢未指定的等效元素排序)。

但是,如果我们改为考虑a == b,那么的想法就可以了。稳定排序实际上需要区分所有三种情况:stable_sorta < ba == b,因此它会两次调用a > b仿函数。

通常,处理这样的优化通常是合理的,并且在某些情况下,为了避免计算时间的指数增长,它是绝对必要的(例如,如果您排序/搜索某些多级别在您知道上级比较的结果之前需要搜索子级别时的容器。)

此外,存储字符串比较的结果可能对后续的排序/搜索/插入操作有用。当然,为了有效地实现这一点,需要一个快速的随机访问容器,它不需要字符串字符迭代(否则它在运行时复杂性上会比仅仅Cmp更差)。如果您的字符串首先规范化,则可能会成为可能。