【问题标题】:Most efficient way to search for a value and return its index in a vector?搜索值并在向量中返回其索引的最有效方法?
【发布时间】:2017-02-26 00:04:46
【问题描述】:

我正在尝试遍历一个向量 (k),并检查它是否包含一个值 (key),如果包含,我想添加在不同向量 (val) 的相同索引处找到的值,然后将在那里找到的任何值添加到第三个向量 (temp)。

for(int i = 0; i < k.size(); ++i)
{
  if(k.at(i) == key)
   {
     temp.push_back(val.at(i));
   } 
}

我最近学到了很多东西,但我在 C++ 方面仍然不是超级先进,这段代码确实可以满足我的目的,但速度非常慢。它可以处理 10 或 100 等大小的小向量,但对于 1000、10000 甚至 1000000 等更大的大小来说,需要的时间太长了。

我的问题是,有没有更快更有效的方法来做到这一点?

我试过了:

std::vector<int>::iterator it = k.begin(); 
while ((iter = std::find(it, k.end(), key)) != k.end()) 
{ 
 int index = std::distance(k.begin(), it); 
 temp.push_back(val.at(index));
} 

我认为使用向量迭代器可能会加快速度,但由于我不确定如何修复的 bad_alloc 错误,我无法让代码工作。

有谁知道我可以做些什么来让这段代码大大更快?

【问题讨论】:

  • 您需要将数据保存在两个单独的向量中吗?对于地图或无序地图来说,这似乎是一项完美的工作。
  • @krzaq 不,我想我不知道,k 和 val 向量在它们的索引处彼此相等,而且它们的大小也相同。有没有办法可以把它们放在一起?那会加快速度吗?
  • 您花时间查找和复制数据。地图对查找时间有很大帮助。
  • std::unordered_multimap&lt;K,V&gt;std::unordered_map&lt;K, std::vector&lt;V&gt;&gt; 似乎都适合此任务,其中K 是可散列键类型,V 分别是值类型。我包括后者是因为您似乎都想要它们,而不是通过在相等范围内的复制来创建值向量,直接映射到向量可能更高效,特别是如果您可以只使用对包含在地图并避免完全复制

标签: c++ vector indexing


【解决方案1】:

您可以做以下几件事:

  1. temp预先分配数据,使push_back不会造成重复分配:

    temp.reserve(k.size());
    
  2. 如果k 已排序,您可以利用这一事实加快处理速度:

    auto lowerIt = std::lower_bound(k.begin(), k.end(), key);
    auto upperIt = std::upper_bound(k.begin(), k.end(), key);
    
    for (auto it = lowerIt; it != upperIt; ++it)
        temp.push_back(val[it - k.begin()]);
    
  3. at 进行边界检查,所以它比 [] 慢一点。您显然必须保证您永远不会访问超出范围的索引。

【讨论】:

  • 非常有帮助,我已经对其进行了排序并加快了速度,我保留了 [ ] 因为我永远不会访问越界索引,并且我已经预先分配了 temp.
  • 我还没有打算提交该评论,但我不知道发布后如何编辑它们。正如我所说,我做了所有 3 件事,它加快了速度,但不足以处理 10k 或 100k。我注意到,如果我运行具有 1000 个元素的向量,它会在眨眼间从 0 到 1000,但是如果我运行 10,000 个元素,从 0 到 1000 需要 5 倍的时间,你知道为什么会这样吗?可以吗?
  • @Dante 我想说一个 1000 个元素的向量可以存储在 L 缓存中,而不是 RAM,这比 RAM 快。但是有 10,000 个元素,它不能存储在缓存中,因此速度较慢
【解决方案2】:

除了 Rakete 的建议:

如果您的键向量已排序 - 使用 std::binary_search 而不是 std::find,然后迭代直到向量的下一个值/结尾。

如果您可以随意更改数据结构,请将您的数据保存在 std::unordered_multimap 中,并使用 equal_range 访问具有所需键的元素。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-06-16
    • 2022-05-22
    • 2011-08-28
    • 1970-01-01
    • 2014-04-02
    • 2021-06-07
    • 2021-10-13
    相关资源
    最近更新 更多