【问题标题】:How can I get vector's index by its data in C++?如何通过 C++ 中的数据获取向量的索引?
【发布时间】:2013-02-01 15:00:31
【问题描述】:

假设我有一个包含 10000 个对象的 vector<node>

vect[0] to vect[9999]

struct node
{
    int data;
};

假设我想找到包含此数据的向量 id(“444”),它恰好在节点 99 中。

我真的需要做一个 for 循环来遍历所有元素然后使用

if (data == c[i].data)

或者有更快的方法吗?考虑到我的数据是不同的,不会在其他 nodes 中重复。

【问题讨论】:

  • 元素是否排序?
  • 除非您确切知道要查找的元素的位置,否则您必须遍历数组才能找到它。例如,如果您确定它的索引是 99,您可以简单地说 vect[99],并且您知道它包含值 444
  • 如果您可以选择不同的容器,那么 std::map 会更快。
  • “向量 id”是什么意思?您需要 index(正如您在标题中所说)还是真的只需要 element?正如其他人所暗示的那样,为您可能执行的操作选择正确的数据结构非常重要。

标签: c++ search vector


【解决方案1】:

对于这个答案,我假设您已经提交了an informed decision to use a std::vector over the other containers available

我真的必须做一个 for 循环来遍历所有元素吗?

不,您不必滚动for-循环来查找元素。在容器中查找元素的惯用方法是使用标准库中的算法。您是否应该自己滚动实际上取决于具体情况。

帮助您做出决定...

备选方案 1:

std::find() 要求有一个适合您的node 数据类型的相等比较器,这可能很简单:

bool operator ==(node const& l, node const& r)
{
    return l.data == r.data;
}

然后,给定required node,您可以搜索该元素。这将返回一个 iterator(如果您使用的是普通的旧数组,则返回一个 pointer)。如果你需要index,这需要一点计算:

auto i = std::find(v.begin(), v.end(), required);
if (i != v.end())
{
    std::cout << i->data << " found at index " << i - v.begin() << std::endl;
}
else
{
    std::cout << "Item not found" << std::endl;
}

备选方案 2:

如果创建node 太昂贵或者您没有相等运算符,更好的方法是使用std::find_if(),它需要一个谓词(这里我使用一个lambda,因为它很简洁,但你可以use a functor like in this answer):

// Alternative linear search, using a predicate...
auto i = std::find_if(v.begin(), v.end(), [](node const& n){return n.data == 444;});
if (i != v.end())
{
    std::cout << i->data << " found at index " << i - v.begin() << std::endl;
}
else
{
    std::cout << "Item not found" << std::endl;
}

或者有更快的方法吗?

同样,这取决于。 std::find()std::find_if() 以线性时间运行 (O(n)),与您的 for-loop 相同。

也就是说,使用 std::find()std::find_if() 不会涉及对容器的随机访问或索引(它们使用迭代器),但与您的 for-loop 相比,它们可能需要一些额外的代码。

备选方案 3:

如果运行时间很关键并且您的数组已排序(例如使用std::sort()),您可以执行以对数时间运行的二进制搜索(O (日志n))。 std::lower_bound() 实现了对不小于给定值的第一个元素的二进制搜索。不幸的是,它不需要谓词,但需要一个适合您的 node 数据类型的小于比较器,例如:

bool operator <(node const& l, node const& r)
{
    return l.data < r.data;
}

调用类似于std::find(),并返回一个迭代器,但需要额外检查:

auto i = std::lower_bound(v.begin(), v.end(), required);
if (i != v.end() && i->data == required.data)
{
    std::cout << i->data << " found at index " << i - v.begin() << std::endl;
}
else
{
    std::cout << "Item not found" << std::endl;
}

the Algorithms Library 中的这些函数适用于任何提供迭代器的容器,因此从std::vector 切换到另一个容器将是快速且易于测试和维护的。

决定权在你!

[See a demonstration here.]

【讨论】:

    【解决方案2】:

    您应该使用std::find。如果你事先对向量一无所知(比如它被排序),你就无法获得比线性复杂度更快的速度 (O(n))。

    【讨论】:

    • 在这种情况下,使用std::find() 比使用简单的for-loop 可以获得什么优势?
    • @Johnsyweb 你在问为什么内置解决方案比重新发明轮子更好?
    • 我不赞成车轮改造,但我认为“你应该”在答案中保证资格,是的。 std::find() 不返回元素的 index (在编辑问题之前它看起来是必需的)。
    • 为了记录,我不认为这个答案值得反对。
    【解决方案3】:

    如果您想在容器中查找元素,那么vector 不是正确的数据结构。您应该使用有序容器,例如std::setstd::map。由于这些容器中的元素保持有序(排序),我们可以在O(log (n)) 时间找到元素,而不是无序容器的线性时间。

    【讨论】:

      【解决方案4】:

      使用std::find

      vector<int>::Iterator it = find (vect.begin(), vect.end(), 444);
      

      请注意,如果您对向量进行了排序,则可以使其更快。

      【讨论】:

      • it 不是 index,而这正是我们所寻求的。
      【解决方案5】:

      一个巧妙的解决方案是在node 结构中添加一个额外的int index 成员,以便在您拥有该结构的实例时提供数据到索引的映射。在这种情况下,您可能应该将 std::vector 包装在一个 NodeVector 类中,该类将处理索引的更新,例如,您删除一个项目(从元素的索引中减去 1 就足够了,该索引先于被删除的元素这种情况)等等。如果向量不改变元素的数量,那甚至都不是问题。除此之外,如果您不能让结构的实例变大,请使用std::map。遍历容器来查找一个项目并不是很聪明,除非你很少需要这样做,并且让任何复杂的事情都不值得麻烦。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-01-02
        • 2011-01-14
        • 1970-01-01
        • 2021-07-12
        • 2020-08-03
        相关资源
        最近更新 更多