【问题标题】:C++ if statement orderC++ if 语句顺序
【发布时间】:2016-09-13 10:06:24
【问题描述】:

在搜索有序列表时,程序的一部分需要检查两个 c 字符串是否相同(例如{"AAA", "AAB", "ABA", "CLL", "CLZ"})。列表可以变得非常大是可行的,因此速度上的微小改进值得降低可读性。假设您仅限于 C++(请不要建议切换到汇编)。如何改进?

typedef char StringC[5];
void compare (const StringC stringX, const StringC stringY)
{
    // use a variable so compareResult won't have to be computed twice
    int compareResult = strcmp(stringX, stringY);
    if (compareResult < 0) // roughly 50% chance of being true, so check this first
    {
        // no match. repeat with a 'lower' value string
        compare(stringX, getLowerString() );
    }
    else if (compareResult > 0) // roughly 49% chance of being true, so check this next
    {
        // no match. repeat with a 'higher' value string
        compare(stringX, getHigherString() );
    }
    else // roughly 1% chance of being true, so check this last
    {
        // match
        reportMatch(stringY);
    }
}

您可以假设stringXstringY 的长度始终相同,您不会得到任何无效的数据输入。

据我了解,编译器将编写代码,以便 CPU 将检查第一个 if 语句并在它为假时跳转,因此最好是第一个语句最有可能为真,因为跳转干扰管道。我还听说在进行比较时,[n Intel] CPU 将进行减法并查看标志的状态,而不保存减法的结果。有没有办法只执行一次strcmp,而不将结果保存到变量中,但仍然能够在前两个 if 语句中检查该结果?

【问题讨论】:

  • 我建议您切换到 C++(目前您的 C 代码具有 C++ 语法的 touch)。关于代码路径的微优化:不要费心去猜测,检查生成的程序集输出(你可能会感到惊讶...)而且往往更重要的输入模式 (有多少个连续的&lt; 0?)比最常见的代码路径。最后说明:如果您在 C 中执行此操作,您可能希望使用 memcmp 而不是 strcmp 来处理 固定长度字符串
  • “只做一次 strcmp 的方法,而不将结果保存到变量中,” 为什么?! strcmp 无论如何都会以 int 的形式生成结果。已经为此目的分配了一个变量。如果您不存储在compareResult 中,您将一无所获。如果你选择 C ​​风格的语法,你现在的代码看起来不错。
  • compare 是提高程序运行时间的错误级别。您提到它是一个有序序列,因此更好的方法不是对您的序列进行线性搜索(我猜),而是二进制搜索。由于您使用的是 C++,因此您可以使用适当的容器(例如:std::set&lt;std::string&gt;)来为您处理此类算法改进。
  • @FrerichRaabe,您不能进行二进制搜索,主要是因为您不知道相等的字符串在字符串空间中的位置。您必须进行线性搜索,但仅将每个字符串 与数组中的下一个字符串进行比较,因为您知道数组已排序,您知道如果数组中有两个相等的字符串,它们必须在一起.
  • @LuisColorado 我不明白 - 我的理解是 OP 想要测试某个 C 字符串是否是其他(有序)C 字符串集的成员。为此,他实现了一个compare 函数,该函数比较两个字符串,然后尝试选择下一个要与之比较的字符串。我的评论是,这似乎是在排序的值序列中测试成员资格的基本问题,而且这个问题已经解决了——根本不需要单独的 compare 函数。

标签: c++ performance search c-strings


【解决方案1】:

std::binary_search 可能会有所帮助:

bool cstring_less(const char (&lhs)[4], const char (&rhs)[4])
{
    return std::lexicographical_compare(std::begin(lhs), std::end(lhs),
                                        std::begin(rhs), std::end(rhs));
}

int main(int, char**)
{
    const char cstrings[][4] = {"AAA", "AAB", "ABA", "CLL", "CLZ"};
    const char lookFor[][4] = {"BBB", "ABA", "CLS"};

    for (const auto& s : lookFor)
    {
        if (std::binary_search(std::begin(cstrings), std::end(cstrings),
                               s, cstring_less))
        {
            std::cout << s << " Found.\n";
        }
    }
}

Demo

【讨论】:

  • ...有序列表 jarod。可以在线性时间内完成,还是我误解了这个问题?我们是在寻找重复还是寻找候选人?
  • @RichardHodges:我提出了一个对数解决方案(在cstring_less 调用中),它比线性时间要好。
  • 我想我对这个问题的理解与你不同。我在想它是在要求检查重复项。我认为你是对的。
  • 只需将每个元素与下一个元素进行比较,即可解决查找重复元素的问题。
  • @Jarod42,你不能,因为重复的字符串可以出现在有序字符串列表中的任何位置。您只能选择进行线性搜索以找到它们。您所知道的是,两个相等的字符串(如果存在)将一起排列在一个有序数组中。所以问题是线性的O(N)。唯一的改进是计算哈希(不是很大的改进)并且已经作为答案发布。
【解决方案2】:

我认为使用哈希表可以大大提高比较的速度。此外,如果您的程序是多线程的,您可以在英特尔线程构建块库中找到一些有用的哈希表。例如 tbb::concurrent_unordered_map 和 std::unordered_map 有相同的 api

希望对你有帮助。

【讨论】:

  • 恐怕不会,至少不会剧烈。如果两个字符串在已排序的数组中相同,则只需将每个元素与下一个元素进行比较,因此您只需对每个元素进行两次比较(一个与前一个元素,另一个与下一个元素)要计算每个元素的哈希值,如果比较(哈希值)结果匹配,您必须进行一次比较: 结果:您计算哈希值并比较哈希值,而不是比较字符串。哈希计算比字符串比较便宜,但算法并没有大幅改进
  • 当然,如果您使用哈希表(不是这种情况),您只需搜索具有多个条目的哈希列表(但您需要再次线性搜索哈希数组)然后比较条目(丢弃散列冲突,即 不同 散列到相同值的条目)所以这不是使用与每个数组条目关联的散列值的预期改进。
【解决方案3】:

如果您尝试将所有字符串相互比较,您将遇到O(N*(N-1)) 问题。正如您所说,列表可能会变大,最好的办法是对它们进行排序(qsort 算法有 O(N*log(N))然后将每个元素与列表中的下一个元素进行比较,这增加了一个新的O(N) 放弃了O(N*log(N)) 的总复杂性。由于您有列表已经订购,您可以遍历它(制作O(N)),将每个元素与下一个元素进行比较。下面是一个在 C 和 C++ 中有效的示例:

for(i = 0; i < N-1; i++)  /* one comparison less than the number of elements */
    if (strcmp(array[i], array[i+1]) == 0) 
        break;
if (i < N-1) {  /* this is a premature exit from the loop, so we found a match */
    /* found a match, array[i] equals array[i+1] */
} else { /* we exhausted al comparisons and got out normally from the loop */
    /* no match found */
}

【讨论】:

猜你喜欢
  • 2017-10-26
  • 2014-04-11
  • 2015-01-16
  • 2023-03-25
  • 1970-01-01
  • 1970-01-01
  • 2013-05-18
  • 2011-04-22
  • 2020-12-10
相关资源
最近更新 更多