【问题标题】:C++ get index of element of array by valueC ++按值获取数组元素的索引
【发布时间】:2023-03-24 02:40:01
【问题描述】:

到目前为止,我一直将数组存储在一个向量中,然后循环遍历该向量以找到匹配的元素,然后返回索引。

在 C++ 中有没有更快的方法来做到这一点?我用来存储数组的 STL 结构对我来说并不重要(它不一定是向量)。我的数组也是唯一的(没有重复的元素)并且是有序的(例如,一个及时向前的日期列表)。

【问题讨论】:

    标签: c++ arrays stl indexing


    【解决方案1】:

    如果要将值与索引关联并快速找到索引,可以使用std::mapstd::unordered_map。您还可以将它们与其他数据结构(例如 std::liststd::vector)结合起来,具体取决于您要对数据执行的其他操作。

    例如,在创建向量时,我们还创建了一个查找表:

    vector<int> test(test_size);
    unordered_map<int, size_t> lookup;
    int value = 0;
    for(size_t index = 0; index < test_size; ++index)
    {
        test[index] = value;
        lookup[value] = index;
        value += rand()%100+1;
    }
    

    现在来查找您简单的索引:

    size_t index = lookup[find_value];
    

    使用基于哈希表的数据结构(例如 unordered_map)是一种相当经典的空间/时间折衷方案,当您需要进行大量查找时,这种“反向”查找操作的二分查找性能会更好。另一个优点是它在向量未排序时也可以工作。

    为了好玩 :-) 我在 VS2012RC 中做了一个快速基准测试,将 James 的二进制搜索代码与线性搜索以及使用 unordered_map 进行查找进行了比较,所有这些都在向量上:

    对于 ~50000 个元素,unordered_set 显着 (x3-4) 优于表现出预期的 O(log N) 行为的二分搜索,有点令人惊讶的结果是 unordered_map 在 10000 个元素之后失去了它的 O(1) 行为,大概是由于散列冲突,可能是一个实现问题。

    编辑:无序映射的 max_load_factor() 为 1,因此应该没有冲突。对于非常大的向量,二分查找和哈希表之间的性能差异似乎与缓存相关,并且取决于基准中的查找模式。

    Choosing between std::map and std::unordered_map 谈论有序映射和无序映射的区别。

    【讨论】:

      【解决方案2】:

      由于元素已排序,您可以使用二进制搜索来查找匹配的元素。 C++ 标准库有一个std::lower_bound 算法可用于此目的。为了清晰和简单,我建议将其包装在您自己的二进制搜索算法中:

      /// Performs a binary search for an element
      ///
      /// The range `[first, last)` must be ordered via `comparer`.  If `value` is
      /// found in the range, an iterator to the first element comparing equal to
      /// `value` will be returned; if `value` is not found in the range, `last` is
      /// returned.
      template <typename RandomAccessIterator, typename Value, typename Comparer>
      auto binary_search(RandomAccessIterator const  first,
                         RandomAccessIterator const  last,
                         Value                const& value,
                         Comparer                    comparer) -> RandomAccessIterator
      {
          RandomAccessIterator it(std::lower_bound(first, last, value, comparer));
          if (it == last || comparer(*it, value) || comparer(value, *it))
              return last;
      
          return it;
      }
      

      (C++ 标准库有一个std::binary_search,但它返回一个bool:如果范围包含该元素,则返回true,否则返回false。如果您想要元素的迭代器,则它没有用。)

      一旦有了元素的迭代器,就可以使用std::distance 算法计算范围内元素的索引。

      这两种算法同样适用于任何随机访问序列,包括std::vector 和普通数组。

      【讨论】:

      • @Ulterior:是的,它是从我的 CxxReflect 库中复制粘贴的。见algorithm.hpp
      • @Ulterior 你需要一个支持一些 C++11 的编译器,尽管该算法可以很容易地用 C++03 编写。
      • 谢谢,我还在 C99 ATM 中
      • @Ulterior:这根本不是 C,而是 C++。
      • @JamesMcNellis 我在某种程度上了解 C++,谢谢,我只是觉得它在某种程度上很奇怪
      猜你喜欢
      • 2011-12-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-11-26
      • 2014-12-15
      • 1970-01-01
      • 1970-01-01
      • 2012-09-06
      相关资源
      最近更新 更多