【问题标题】:Reuse result of string comparison for faster std::sort重用字符串比较的结果以获得更快的 std::sort
【发布时间】:2018-01-29 21:35:12
【问题描述】:

我想用 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;
});

为了限制存储的信息和额外引入的比较次数,我想只存储right字符串,这成为逆比较的左边。

现在,我的实际问题是仅检查以前的 right 字符串是否足够,还是我还需要存储和检查以前的 left 字符串?

【问题讨论】:

  • 标准库可以复制谓词任意次数。
  • “还需要判断字符串是否相等”。你是说std::sort 需要确定吗?它没有。
  • 在这种情况下,谓词将使用相同的字符串但以相反的参数顺序再次调用。 -- 据我所知,这仅在调试运行时实现中完成std::sort 运行时正在检查您的谓词是否遵循 strict-weak-order。否则,您无法推测您将在谓词中获得哪两项。
  • @HenriMenke qsortstd::sort 相比是原始的,并且通常更慢。它使用三向比较的能力并没有给它带来任何优势。
  • 如果有太空船操作员,可能会添加更快的std::sort 版本。 open-std.org/JTC1/SC22/WG21/docs/papers/2017/p0515r0.pdf

标签: c++ string sorting predicate strcmp


【解决方案1】:

首先,您的假设是错误的。 std::sort 不会用相同的参数调用两次比较。因此,整个想法是有缺陷的。

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

【讨论】:

  • 您的说法不正确:std::sort 在 VS 2017 发布的 STL 实现中使用分区快速排序,并且它使用双向比较。其次,复制有状态谓词时不会发生任何非法行为。存储状态的变量仅在可能的情况下用于优化。我的问题是关于只检查一个字符串来检测双向比较是否安全,或者我是否需要同时检查两个字符串
【解决方案2】:

是的,在这里提出的情况下,这个想法没有用,因为 sort 不需要区分确切的等价 - 它可以轻松地混合 a &gt; ba == b 情况(感谢未指定的排序等效元素)。

但是,如果我们改为考虑stable_sort,这个想法确实奏效。稳定排序实际上需要区分所有三种情况:a &lt; ba == ba &gt; b,所以它会调用Cmp 函子两次。

一般来说,进行这种优化通常是合理的,并且在某些情况下,为了避免计算时间呈指数增长(例如,如果您在需要时对某些多级容器进行排序/搜索在你知道上层比较结果之前搜索子层)。

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-06
    • 1970-01-01
    • 2017-02-09
    • 2022-03-30
    相关资源
    最近更新 更多