ChatGPT解决这个技术问题 Extra ChatGPT

如何找出一个项目是否存在于 std::vector 中?

我要做的就是检查向量中是否存在元素,这样我就可以处理每种情况。

if ( item_present )
   do_this();
else
   do_that();
在向量中搜索非常慢,因为您必须查看向量的每个元素,因此如果您要进行大量查找,请考虑使用地图
@naumcho:如果对向量进行排序,则始终存在二进制搜索,如下所示。这使它与映射一样快,如果您只存储值(而不是键/值映射),那么它将使用更少的内存。
maps 肯定不是最佳选择,但使用 set 可能有用。如果您需要 O(1) 查找时间,则 hash_set 是要走的路。
重复问题的绝佳答案:stackoverflow.com/a/3451045/472647
如果您要多次搜索不同的数字,哈希表会更有效。

A
Anselmo GPP

您可以使用 <algorithm> 中的 std::find

#include <algorithm>
#include <vector>
vector<int> vec; 
//can have other data types instead of int but must same datatype as item 
std::find(vec.begin(), vec.end(), item) != vec.end()

这会将迭代器返回到找到的第一个元素。如果不存在,它会返回一个迭代器到最后一个。用你的例子:

#include <algorithm>
#include <vector>

if ( std::find(vec.begin(), vec.end(), item) != vec.end() )
   do_this();
else
   do_that();

我看不出 count() 如何比 find() 快,因为 find() 会在找到一个元素后立即停止,而 count() 总是必须扫描整个序列。
不要忘记 #include <algorithm> 否则您可能会遇到非常奇怪的错误,例如“在命名空间 std 中找不到匹配的函数”
尽管 STL 是“面向对象的”,但 .find() 仍然不是 std::vector 的成员函数,这是否没有让任何人感到困扰,正如您所期望的那样?我想知道这是否是模板化的结果。
@bobobobo:OOP 与成员与非成员无关。并且有一个广泛的思想流派,如果某些东西不必成为成员,或者当它作为成员实施时没有任何优势时,那么它不应该成为成员; std::vector<>::find() 不会带来任何好处,也不需要它,因此,不,它不应该是成员。另请参阅en.wikipedia.org/wiki/Coupling_%28computer_programming%29
@phresnel我认为“当它作为成员实施时没有任何优势时”对于这种情况是错误的。优点是简化和更清晰的界面。例如:mvec.find(key) != mvec.cend() 优于 std::find(mvec.cbegin(), mvec.cend(), key) != mvec.cend()
B
Brian Neal

正如其他人所说,使用 STL findfind_if 函数。但是,如果您在非常大的向量中进行搜索并且这会影响性能,您可能需要对向量进行排序,然后使用 binary_searchlower_boundupper_bound 算法。


好答案!查找总是 o(n)。如果与随机访问迭代器一起使用,lower_bound 为 o(log(n))。
不过,排序是 O(nlogn),所以只有当你做的搜索超过 O(logn) 时才值得。
@liori 是的,这取决于您的使用模式。如果您只需要对其进行一次排序,那么重复进行多次搜索可以节省您的时间。
@Brian Neal,如果必须对其进行许多元素搜索,那么对大向量进行排序是值得的。排序将是 O(nlogn),如果一个元素只能找到一次,O(n) 会更好:)
请注意,这可能会对您的分支预测造成严重破坏。
h
hfossli

如果您的向量未排序,请使用 MSN 建议的方法:

if(std::find(vector.begin(), vector.end(), item)!=vector.end()){
      // Found the item
}

如果您的向量是有序的,请使用 Brian Neal 建议的 binary_search 方法:

if(binary_search(vector.begin(), vector.end(), item)){
     // Found the item
}

二分搜索产生 O(log n) 最坏情况的性能,这比第一种方法更有效。为了使用二分查找,您可以先使用 qsort 对向量进行排序,以保证它是有序的。


你不是说std::sort吗? qsort 在向量上的效率非常低....参见:stackoverflow.com/questions/12308243/…
对于较大的容器,二分搜索的性能会更好,但对于小型容器,简单的线性搜索可能会一样快,甚至更快。
@BillT:体面的二进制搜索实现不会将自身切换到低于某个阈值元素数的线性搜索吗?
i
isanae

使用 stl 的算法头中的 find。我已经说明了它与 int 类型的用法。您可以使用任何您喜欢的类型,只要您可以比较是否相等(如果您需要为您的自定义类重载 ==)。

#include <algorithm>
#include <vector>

using namespace std;
int main()
{   
    typedef vector<int> IntContainer;
    typedef IntContainer::iterator IntIterator;

    IntContainer vw;

    //...

    // find 5
    IntIterator i = find(vw.begin(), vw.end(), 5);

    if (i != vw.end()) {
        // found it
    } else {
        // doesn't exist
    }

    return 0;
}

根据 OP 的需要, find_if() 也可能是合适的。它允许使用任意谓词而不是相等进行搜索。
哎呀,看到你的评论太晚了。我给出的答案也提到了 find_if。
L
L. F.

在 C++11 中,您可以使用 any_of。例如,如果它是 vector<string> v;,则:

if (any_of(v.begin(), v.end(), bind(equal_to<string>(), _1, item)))
   do_this();
else
   do_that();

或者,使用 lambda:

if (any_of(v.begin(), v.end(), [&](const std::string& elem) { return elem == item; }))
   do_this();
else
   do_that();

bind1stbind2nddeprecated since C++11 并在 C++17 中完全删除。将 bindplaceholders 和/或 lambda 一起使用。
既然有 std::find(),为什么还要使用 std::any_of()
如果目的只是为了检查成员资格,为什么我们有 std::any_of 时还要使用 std::find()
C
Community

我用这样的东西......

#include <algorithm>


template <typename T> 
const bool Contains( std::vector<T>& Vec, const T& Element ) 
{
    if (std::find(Vec.begin(), Vec.end(), Element) != Vec.end())
        return true;

    return false;
}

if (Contains(vector,item))
   blah
else
   blah

...那样它实际上是清晰易读的。 (显然你可以在多个地方重用模板)。


您可以使用 2 个类型名使其适用于列表或向量
@ErikAronesty 如果您使用容器中的 value_type 作为元素类型,则可以使用 1 个模板参数。我已经添加了这样的答案。
您基本上是在写:if true return true else return false。该方法可以是一个:return std::find(Vec.begin(), Vec.end(), Element) != Vec.end();
M
Martin Broadhurst

这是一个适用于任何容器的函数:

template <class Container> 
const bool contains(const Container& container, const typename Container::value_type& element) 
{
    return std::find(container.begin(), container.end(), element) != container.end();
}

请注意,您可以使用 1 个模板参数,因为您可以从容器中提取 value_type。您需要 typename,因为 Container::value_typedependent name


请注意,这有时有点过于宽泛——例如,它适用于 std::set,但与 find() 成员函数相比,性能很差。我发现最好为具有更快搜索的容器添加专业化(set/map,unordered_*)
也许有一天他们最终会将它添加到标准库中......而不是人们不得不一遍又一遍地询问如何重新发明这样一个小轮子。现在完全可行的是,在 C++20 中我们有 ranges,所以它可以被称为 Range 而不是 Container,并且 Bob 是你的叔叔。
您如何看待 @PascalLaferrière 的 approach 推导值类型?
D
David Thornley

请记住,如果您要进行大量查找,那么 STL 容器会更适合您。我不知道您的应用程序是什么,但像 std::map 这样的关联容器可能值得考虑。

std::vector 是首选容器,除非您有另一个原因,并且按值查找可能是这样的原因。


即使通过值查找,向量也是一个不错的选择,只要它已排序并且您使用 binary_search、lower_bound 或 upper_bound。如果容器的内容在查找之间发生变化,vector 就不是很好,因为需要重新排序。
F
Frank

使用 STL find 函数。

请记住,还有一个 find_if 函数,如果您的搜索更复杂,您可以使用它,即如果您不只是在寻找一个元素,而是,例如,想看看是否有一个元素满足特定条件,例如以“abc”开头的字符串。 (find_if 会给你一个指向第一个这样的元素的迭代器)。


M
Mikhail

借助 boost,您可以使用 any_of_equal

#include <boost/algorithm/cxx11/any_of.hpp>

bool item_present = boost::algorithm::any_of_equal(vector, element);

T
TrungTN

你可以试试这段代码:

#include <algorithm>
#include <vector>

// You can use class, struct or primitive data type for Item
struct Item {
    //Some fields
};
typedef std::vector<Item> ItemVector;
typedef ItemVector::iterator ItemIterator;
//...
ItemVector vtItem;
//... (init data for vtItem)
Item itemToFind;
//...

ItemIterator itemItr;
itemItr = std::find(vtItem.begin(), vtItem.end(), itemToFind);
if (itemItr != vtItem.end()) {
    // Item found
    // doThis()
}
else {
    // Item not found
    // doThat()
}

T
TankorSmash

您可以使用 std 命名空间中的 find 函数,即 std::find。您将要搜索的向量中的 beginend 迭代器以及要查找的元素传递给 std::find 函数,并将生成的迭代器与向量的末尾进行比较以查看它们是否匹配或不是。

std::find(vector.begin(), vector.end(), item) != vector.end()

您还可以取消引用该迭代器并像任何其他迭代器一样正常使用它。


P
Pang

您也可以使用计数。它将返回向量中存在的项目数。

int t=count(vec.begin(),vec.end(),item);

findcount 快,因为它不会在第一场比赛后继续计数。
u
user3157855
template <typename T> bool IsInVector(const T & what, const std::vector<T> & vec)
{
    return std::find(vec.begin(),vec.end(),what)!=vec.end();
}

为什么您要使用指针并冒险让用户通过您不处理的 nullptr?根本没有必要。此外,您复制 T what,这可能很昂贵并且是不必要的工作。这两个参数都应该是 const 引用而不是它们当前的引用。最后,我不知道为什么人们会写 if (condition) return true; else return false;,而他们本来可以写 return condition;
感谢您的建议,当时我没有太多经验并同时切换到 Java :) 我更新了评论,让我知道它是否更好或者是否还有需要修复的地方。
现在您收到的是引用而不是指针,您需要使用 . 而不是 ->
如果您希望将 std::find() 调整为可用于容器,请以一般方式进行,而不仅仅是向量。或许可以称它为 find()stdx::find() 之类的。
P
Pascal Laferrière

我个人最近使用模板来一次处理多种类型的容器,而不是只处理向量。我在网上找到了一个类似的例子(不记得在哪里)所以归功于我从谁那里偷来的。这种特殊的模式似乎也可以处理原始数组。

template <typename Container, typename T = typename std::decay<decltype(*std::begin(std::declval<Container>()))>::type>
bool contains(Container && c, T v)
{
    return std::find(std::begin(c), std::end(c), v) != std::end(c);
}

请考虑将 value-type-deduction 逻辑分离为它自己的 trait,例如 template <typename Container> struct value_type { ... etc. ... }
@einpoklum 我对模板逻辑还很陌生,老实说,我几乎无法理解这个解决方案是如何发挥它的魔力的。您可以扩展 {...etc...} 吗?
G
Gank

如果你想在向量中找到一个字符串:

    struct isEqual
{
    isEqual(const std::string& s): m_s(s)
    {}

    bool operator()(OIDV* l)
    {
        return l->oid == m_s;
    }

    std::string m_s;
};
struct OIDV
{
    string oid;
//else
};
VecOidv::iterator itFind=find_if(vecOidv.begin(),vecOidv.end(),isEqual(szTmp));

std::find 在这种情况下很好,不需要谓词对象。
P
Pavan Chandaka

(C++17 及以上):

也可以使用 std::search

这对于搜索元素序列也很有用。

#include <algorithm>
#include <iostream>
#include <vector>

template <typename Container>
bool search_vector(const Container& vec, const Container& searchvec)
{
    return std::search(vec.begin(), vec.end(), searchvec.begin(), searchvec.end()) != vec.end();
}

int main()
{
     std::vector<int> v = {2,4,6,8};

     //THIS WORKS. SEARCHING ONLY ONE ELEMENT.
     std::vector<int> searchVector1 = {2};
     if(search_vector(v,searchVector1))
         std::cout<<"searchVector1 found"<<std::endl;
     else
         std::cout<<"searchVector1 not found"<<std::endl;

     //THIS WORKS, AS THE ELEMENTS ARE SEQUENTIAL.
     std::vector<int> searchVector2 = {6,8};
     if(search_vector(v,searchVector2))
         std::cout<<"searchVector2 found"<<std::endl;
     else
         std::cout<<"searchVector2 not found"<<std::endl;

     //THIS WILL NOT WORK, AS THE ELEMENTS ARE NOT SEQUENTIAL.
     std::vector<int> searchVector3 = {8,6};
     if(search_vector(v,searchVector3))
         std::cout<<"searchVector3 found"<<std::endl;
     else
         std::cout<<"searchVector3 not found"<<std::endl;
}

还有传递一些搜索算法的灵活性。参考这里。

https://en.cppreference.com/w/cpp/algorithm/search


std::search 用于搜索范围内的多个值中的任何一个;对于单个值,没有理由使用它。
P
Pavan Chandaka

从 C++20 开始,使用范围 (#include <ranges>)

    //SAMPLE DATA
    std::vector<int> vecOfElements = { 2,4,6,8 };

    //DO SOMETHING IF 8 IN VECTOR
    if (std::ranges::find(vecOfElements, 8) != vecOfElements.end())
    {
        std::cout << "DO SOMETHING" << std::endl;
    }