la recherche dans un vecteur est très lente car vous devez regarder chaque élément du vecteur, alors pensez à utiliser une carte si vous faites beaucoup de recherches
naumcho
7
@naumcho: Si le vecteur est trié, il y a toujours une recherche binaire, comme indiqué ci-dessous. Cela le rend aussi rapide qu'une carte et si vous ne stockez que des valeurs (pas des cartes de clés / valeurs), cela va utiliser beaucoup moins de mémoire.
Adam Hawes
4
les cartes ne sont certainement pas le meilleur choix, mais l'utilisation de set peut être utile. Si vous avez besoin du temps de recherche O (1), hash_set est le chemin à parcourir.
Si vous cherchez plusieurs fois des nombres différents, une table de hachage serait plus efficace.
NL628
Réponses:
916
Vous pouvez utiliser à std::findpartir de <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()
Cela renvoie un booléen ( trues'il est présent, falsesinon). Avec votre exemple:
Je ne vois pas comment count () pourrait être plus rapide que find (), car find () s'arrête dès qu'un élément est trouvé, tandis que count () doit toujours parcourir toute la séquence.
Éric Malenfant le
114
N'oubliez pas, #include <algorithm>sinon vous pourriez obtenir des erreurs très étranges comme «
Impossible de
80
Cela n'a-t-il pas dérangé personne que, bien que la STL soit "orientée objet", elle .find()n'est toujours pas une fonction membre std::vector, comme vous vous en doutez? Je me demande si c'est en quelque sorte une conséquence des modèles.
bobobobo
71
@bobobobo: OOP n'a rien à voir avec les membres par rapport aux non-membres. Et il y a une école de pensée répandue que si quelque chose n'a pas à être membre, ou quand il ne donne aucun avantage lorsqu'il est mis en œuvre en tant que membre, alors il ne devrait pas être membre; std::vector<>::find()ne donnerait aucun avantage et n’est pas nécessaire. Par conséquent, non, il ne devrait pas être membre. Voir aussi en.wikipedia.org/wiki/Coupling_%28computer_programming%29
Sebastian Mach
36
@phresnel Je dirais que "quand cela ne donne aucun avantage lorsqu'il est implémenté en tant que membre" est faux pour ce cas. L'avantage étant une interface simplifiée et plus claire. Par exemple: mvec.find(key) != mvec.cend()est préférable à std::find(mvec.cbegin(), mvec.cend(), key) != mvec.cend().
swalog
113
Comme d'autres l'ont dit, utilisez la STL findou les find_iffonctions. Mais si vous êtes à la recherche dans des vecteurs très importants et cette performance impacts, vous pouvez trier votre vecteur, puis utilisez les binary_search, lower_boundou des upper_boundalgorithmes.
Bonne réponse! La recherche est toujours o (n). lower_bound est o (log (n)) s'il est utilisé avec des itérateurs à accès aléatoire.
Stephen Edmonds, le
30
Le tri est cependant O (nlogn), donc cela ne vaut que si vous effectuez plus de recherches O (logn).
liori
7
@liori Vrai, cela dépend de vos habitudes d'utilisation. Si vous n'avez besoin de le trier qu'une seule fois, effectuez de nombreuses recherches à plusieurs reprises, cela peut vous sauver.
Brian Neal
1
@Brian Neal, trier un grand vecteur vaut la peine s'il doit y avoir de nombreuses recherches d'éléments. Le tri sera O (nlogn) et O (n) sera meilleur s'il ne faut trouver un élément qu'une seule fois :)
Swapnil B.
47
Utilisez find à partir de l'en-tête de l'algorithme de stl. J'ai illustré son utilisation avec le type int. Vous pouvez utiliser n'importe quel type que vous aimez tant que vous pouvez comparer pour l'égalité (surcharge == si vous en avez besoin pour votre classe personnalisée).
#include<algorithm>#include<vector>usingnamespace std;int main(){typedefvector<int>IntContainer;typedefIntContainer::iteratorIntIterator;IntContainer vw;//...// find 5IntIterator i = find(vw.begin(), vw.end(),5);if(i != vw.end()){// found it}else{// doesn't exist}return0;}
Selon les besoins de l'OP, find_if () pourrait également être approprié. Il permet de rechercher en utilisant un prédicat arbitraire au lieu de l'égalité.
Éric Malenfant
Oups, vous avez vu votre commentaire trop tard. La réponse que j'ai donnée mentionne également find_if.
Frank
39
Si votre vecteur n'est pas ordonné, utilisez l'approche suggérée par MSN:
if(std::find(vector.begin(),vector.end(), item)!=vector.end()){// Found the item}
Si votre vecteur est ordonné, utilisez la méthode binary_search Brian Neal a suggéré:
if(binary_search(vector.begin(),vector.end(), item)){// Found the item}
la recherche binaire donne les performances du pire des cas O (log n), ce qui est beaucoup plus efficace que la première approche. Afin d'utiliser la recherche binaire, vous pouvez utiliser qsort pour trier d'abord le vecteur pour garantir qu'il est ordonné.
La recherche binaire fonctionnera mieux pour les grands conteneurs, mais pour les petits conteneurs, une simple recherche linéaire sera probablement aussi rapide ou plus rapide.
et vous pouvez le faire fonctionner pour les listes ou les vecteurs en utilisant 2 noms de caractères
Erik Aronesty
@ErikAronesty, vous pouvez vous en tirer avec 1 argument de modèle si vous utilisez value_typele conteneur pour le type d'élément. J'ai ajouté une réponse comme celle-ci.
Martin Broadhurst
13
En C ++ 11, vous pouvez utiliser any_of. Par exemple, si c'est un vector<string> v;alors:
Notez que vous pouvez vous en tirer avec 1 paramètre de modèle, car vous pouvez extraire le value_typedu conteneur. Vous avez besoin du typenamecar Container::value_typeest un nom dépendant .
Notez que c'est parfois un peu trop large - cela fonctionnerait pour std :: set par exemple, mais donnerait des performances terribles par rapport à la fonction membre find (). J'ai trouvé préférable d'ajouter une spécialisation pour les conteneurs avec une recherche plus rapide (set / map, unordered_ *)
Andy Krouwel
10
Gardez à l'esprit que, si vous effectuez de nombreuses recherches, il existe des conteneurs STL qui conviennent mieux à cela. Je ne sais pas quelle est votre application, mais les conteneurs associatifs comme std :: map peuvent être intéressants.
std :: vector est le conteneur de choix, sauf si vous avez une raison pour une autre, et les recherches par valeur peuvent être une telle raison.
Même avec des recherches par valeur, le vecteur peut être un bon choix, tant qu'il est trié et que vous utilisez binary_search, lower_bound ou upper_bound. Si le contenu du conteneur change entre les recherches, le vecteur n'est pas très bon en raison de la nécessité de trier à nouveau.
Gardez à l'esprit qu'il existe également une fonction find_if , que vous pouvez utiliser si votre recherche est plus complexe, c'est-à-dire si vous ne recherchez pas seulement un élément, mais, par exemple, vous voulez voir s'il y a un élément qui remplit un certain condition, par exemple, une chaîne commençant par "abc". ( find_ifvous donnerait un itérateur qui pointe vers le premier élément de ce type).
#include<algorithm>#include<vector>// You can use class, struct or primitive data type for ItemstructItem{//Some fields};typedef std::vector<Item>ItemVector;typedefItemVector::iteratorItemIterator;//...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()}
Vous pouvez utiliser la findfonction, trouvée dans l' stdespace de noms, c'est-à-dire std::find. Vous passez la std::findfonction beginet l' enditérateur du vecteur que vous souhaitez rechercher, ainsi que l'élément que vous recherchez et comparez l'itérateur résultant à la fin du vecteur pour voir s'ils correspondent ou non.
Ceci est également utile pour rechercher une séquence d'éléments.
#include<algorithm>#include<iostream>#include<vector>template<typenameContainer>bool search_vector(constContainer& vec,constContainer& 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;}
Il est également possible de passer certains algorithmes de recherche. Reportez-vous ici.
J'ai personnellement utilisé des modèles récemment pour gérer plusieurs types de conteneurs à la fois plutôt que de traiter uniquement des vecteurs. J'ai trouvé un exemple similaire en ligne (je ne me souviens pas d'où), donc le mérite revient à qui que ce soit. Ce modèle particulier semble également gérer les tableaux bruts.
template<typenameContainer,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);}
Réponses:
Vous pouvez utiliser à
std::find
partir de<algorithm>
:Cela renvoie un booléen (
true
s'il est présent,false
sinon). Avec votre exemple:la source
#include <algorithm>
sinon vous pourriez obtenir des erreurs très étranges comme «.find()
n'est toujours pas une fonction membrestd::vector
, comme vous vous en doutez? Je me demande si c'est en quelque sorte une conséquence des modèles.std::vector<>::find()
ne donnerait aucun avantage et n’est pas nécessaire. Par conséquent, non, il ne devrait pas être membre. Voir aussi en.wikipedia.org/wiki/Coupling_%28computer_programming%29mvec.find(key) != mvec.cend()
est préférable àstd::find(mvec.cbegin(), mvec.cend(), key) != mvec.cend()
.Comme d'autres l'ont dit, utilisez la STL
find
ou lesfind_if
fonctions. Mais si vous êtes à la recherche dans des vecteurs très importants et cette performance impacts, vous pouvez trier votre vecteur, puis utilisez lesbinary_search
,lower_bound
ou desupper_bound
algorithmes.la source
Utilisez find à partir de l'en-tête de l'algorithme de stl. J'ai illustré son utilisation avec le type int. Vous pouvez utiliser n'importe quel type que vous aimez tant que vous pouvez comparer pour l'égalité (surcharge == si vous en avez besoin pour votre classe personnalisée).
la source
Si votre vecteur n'est pas ordonné, utilisez l'approche suggérée par MSN:
Si votre vecteur est ordonné, utilisez la méthode binary_search Brian Neal a suggéré:
la recherche binaire donne les performances du pire des cas O (log n), ce qui est beaucoup plus efficace que la première approche. Afin d'utiliser la recherche binaire, vous pouvez utiliser qsort pour trier d'abord le vecteur pour garantir qu'il est ordonné.
la source
std::sort
?qsort
est très inefficace sur les vecteurs .... voir: stackoverflow.com/questions/12308243/…J'utilise quelque chose comme ça ...
... comme ça c'est en fait clair et lisible. (Évidemment, vous pouvez réutiliser le modèle à plusieurs endroits).
la source
value_type
le conteneur pour le type d'élément. J'ai ajouté une réponse comme celle-ci.En C ++ 11, vous pouvez utiliser
any_of
. Par exemple, si c'est unvector<string> v;
alors:Vous pouvez également utiliser un lambda:
la source
bind1st
etbind2nd
sont obsolètes depuis C ++ 11 et complètement supprimés en C ++ 17. Utilisez plutôtbind
avecplaceholders
et / ou lambdas.Voici une fonction qui fonctionnera pour n'importe quel conteneur:
Notez que vous pouvez vous en tirer avec 1 paramètre de modèle, car vous pouvez extraire le
value_type
du conteneur. Vous avez besoin dutypename
carContainer::value_type
est un nom dépendant .la source
Gardez à l'esprit que, si vous effectuez de nombreuses recherches, il existe des conteneurs STL qui conviennent mieux à cela. Je ne sais pas quelle est votre application, mais les conteneurs associatifs comme std :: map peuvent être intéressants.
std :: vector est le conteneur de choix, sauf si vous avez une raison pour une autre, et les recherches par valeur peuvent être une telle raison.
la source
Utilisez la fonction de recherche STL .
Gardez à l'esprit qu'il existe également une fonction find_if , que vous pouvez utiliser si votre recherche est plus complexe, c'est-à-dire si vous ne recherchez pas seulement un élément, mais, par exemple, vous voulez voir s'il y a un élément qui remplit un certain condition, par exemple, une chaîne commençant par "abc". (
find_if
vous donnerait un itérateur qui pointe vers le premier élément de ce type).la source
Avec boost, vous pouvez utiliser
any_of_equal
:la source
Vous pouvez essayer ce code:
la source
Vous pouvez utiliser la
find
fonction, trouvée dans l'std
espace de noms, c'est-à-direstd::find
. Vous passez lastd::find
fonctionbegin
et l'end
itérateur du vecteur que vous souhaitez rechercher, ainsi que l'élément que vous recherchez et comparez l'itérateur résultant à la fin du vecteur pour voir s'ils correspondent ou non.Vous pouvez également déréférencer cet itérateur et l'utiliser normalement, comme n'importe quel autre itérateur.
la source
Vous pouvez également utiliser le comptage. Il renverra le nombre d'éléments présents dans un vecteur.
la source
find
est plus rapide quecount
, car il ne continue pas de compter après le premier match.Si vous voulez trouver une chaîne dans un vecteur:
la source
Un autre exemple utilisant des opérateurs C ++.
la source
la source
(C ++ 17 et supérieur):
peut
std::search
également utiliserCeci est également utile pour rechercher une séquence d'éléments.
Il est également possible de passer certains algorithmes de recherche. Reportez-vous ici.
https://en.cppreference.com/w/cpp/algorithm/search
la source
J'ai personnellement utilisé des modèles récemment pour gérer plusieurs types de conteneurs à la fois plutôt que de traiter uniquement des vecteurs. J'ai trouvé un exemple similaire en ligne (je ne me souviens pas d'où), donc le mérite revient à qui que ce soit. Ce modèle particulier semble également gérer les tableaux bruts.
la source
Utiliser Newton C ++ est plus facile, auto-documenté et plus rapide qu'avec std :: find car il renvoie directement un booléen.
Je pense que c'est évident ce que font les fonctions.
la source