【问题标题】:C++ check how many same elements in a row are in a vectorC ++检查向量中有多少行中的相同元素
【发布时间】:2013-05-02 13:10:22
【问题描述】:

我有一个包含 24.000 个元素的大向量,例如:

(1,1,1,1,3,3,3,3,3,3,5,5,5,...etc)

我想检查一行中有多少相同的元素,例如: 4-6-3..等 我使用此代码:

static int counter=1;
vector<int>numbers;

for(int n=0;n<numbers.size()-1;n++)
{
  if(numbers[n]==numbers[n+1])
  {
    counter++;
  }
  else if(numbers[n]!=numbers[n+1])
  {
   cout<<counter<<endl;
   counter=1;
  }
}

有没有比这更快的算法?

【问题讨论】:

  • 向量排序了吗?
  • 您可以删除第二个 if() 语句,并且应该关心最后一个元素
  • @SonicpathSonicwave 是一个包含 {1, 2, 3, 1} 可能输入的向量?
  • @stefan 是的
  • 是的,我知道我总是手动检查最后一个元素不知道如何在代码中做到这一点

标签: c++ algorithm vector stl


【解决方案1】:

您的算法及时为O(N),这对我来说似乎非常理想,因为您必须访问每个独特的元素进行比较。您可能仍然会在这里和那里剃掉几个周期,例如通过消除else() 中的条件 或通过打开一些编译器设置,但从算法上来说,你的状态很好。

如果输入已经排序,您可以进行一系列二分搜索。这会给你O(N lg N) 最坏情况的复杂性,但根据相等元素序列的平均长度,平均情况可能要低得多。

顺便说一句,正如@AndyProwl 在他的回答中所表明的那样:标准库真的很棒,即使是这种低级算法的东西。 adjacent_findupper_bound 算法具有详细记录的复杂性,迭代器约定将保护您避免出现在您自己的代码中的边缘情况。一旦你学会了这个词汇,你就可以很容易地在你自己的例程中使用它们(当 Ranges 出现在 C++ 中时,希望它也会更容易组合它们)。

【讨论】:

    【解决方案2】:

    @rhalbersma 基本上给了你正确的答案。作为附录,如果您想以更标准的方式重写您的算法:

    #include <algorithm>
    #include <vector>
    #include <iterator>
    #include <functional>
    #include <iostream>
    
    int main()
    {
        std::vector<int> v { 1, 1, 2, 3, 3, 5, 5, 5 }; // or whatever...
    
        auto i = begin(v);
        while (i != end(v))
        {
            auto j = adjacent_find(i, end(v), std::not_equal_to<int>());
            if (j == end(v)) { std::cout << distance(i, j); break; }
            std::cout << distance(i, j) + 1 << std::endl;
            i = next(j);
        }
    }
    

    这是live example

    此外,当对向量进行排序时,这将为您提供更好的最佳情况复杂性:

    #include <algorithm>
    #include <vector>
    #include <iterator>
    #include <iostream>
    
    int main()
    {
        std::vector<int> v { 1, 1, 2, 3, 3, 5, 5, 5 }; // must be sorted...
    
        auto i = begin(v);
        while (i != end(v))
        {
            auto ub = upper_bound(i, end(v), *i);
            std::cout << distance(i, ub) << std::endl;
            i = ub;
        }
    }
    

    这是live example

    【讨论】:

    • +1 用于标准库。在我们的示例中,您缺少 using namespace std; 或一些 std:: 限定符。
    • @rhalbersma:除非我犯了一些错误,否则那些std:: 是不必要的,因为 ADL。但是,是的,他们可能在那里;)
    • 啊,你的 ADL 瘾又来了!我们都有自己的恶习:-)(我使用#pragma once,没有其他包括警卫)
    • @rhalbersma:顺便说一句,很抱歉输入错误的用户名
    • 如果没有太多相同的元素,我认为upper_bound 方法不会更快。我相信这种方法最坏的情况是 O(n log n)(但最好的情况是 O(log n)),而本机方法总是 O(n)。此外,从i 开始可能会略有改进 - 类似于upper_bound(i, end(v), *i)
    【解决方案3】:

    有一些小优化可能会给你几毫秒:

    int size = numbers.size()-1;
    static int counter=1;
    static int *num1 = &numbers[0];
    static int *num2 = &numbers[1];
    for(int n=0;n<size;n++)
    {
      if(*num1==*num2) counter++;
      else
      {
       cout << counter << "\n";
       counter=1;
      }
      num1++;
      num2++;
    }
    cout<<counter<<endl; //Caution, this line is missing in your code!!
    

    基本上:

    • 避免通过 id 访问向量:numbers[n] 意味着计算机必须乘以 n*sizeof(int) 并将这个结果添加到 numbers。使用指针并递增它更快,这意味着只是一个添加。

    【讨论】:

    • 然后还删除内部循环中的endl,因为它每次都会刷新缓冲区,而不仅仅是在缓冲区满时。
    • 你是对的!!我已经编辑了这一行。此外,也许有比 iosteam 更有效的方法。
    猜你喜欢
    • 2013-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-10-18
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多