buscar en un vector es muy lento ya que hay que mirar a cada elemento del vector a fin de considerar el uso de un mapa, si está haciendo una gran cantidad de búsquedas
naumcho
77
@naumcho: Si el vector está ordenado, siempre hay una búsqueda binaria, como se publica a continuación. Esto lo hace tan rápido como un mapa y si solo está almacenando valores (no mapas de clave / valor), entonces usará mucha menos memoria.
Adam Hawes
44
los mapas ciertamente no son la mejor opción, pero usar set podría ser útil. Si necesita tiempo de búsqueda O (1), hash_set es el camino a seguir.
#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()
Esto devuelve un bool ( truesi está presente, de lo falsecontrario). Con tu ejemplo:
No veo cómo count () podría ser más rápido que find (), ya que find () se detiene tan pronto como se encuentra un elemento, mientras que count () siempre tiene que escanear toda la secuencia.
Éric Malenfant
114
No te olvides #include <algorithm>o de lo contrario podrías obtener errores muy extraños como 'no se puede encontrar la función de coincidencia en el espacio de nombres
estándar
80
¿No le ha molestado a nadie que, a pesar de que el STL está "orientado a objetos", .find()todavía no es una función miembro std::vector, como cabría esperar? Me pregunto si esto es de alguna manera una consecuencia de la plantilla.
bobobobo
71
@bobobobo: OOP no tiene nada que ver con miembros versus no miembros. Y existe una escuela de pensamiento generalizada de que si algo no tiene que ser miembro, o cuando no ofrece ninguna ventaja cuando se implementa como miembro, entonces no debería ser miembro; std::vector<>::find()no daría ninguna ventaja, ni es necesaria, por lo tanto, no, no debería ser miembro. Ver también en.wikipedia.org/wiki/Coupling_%28computer_programming%29
Sebastian Mach
36
@phresnel Yo diría que "cuando no da ninguna ventaja cuando se implementa como miembro" es falso para este caso. La ventaja es una interfaz simplificada y más clara. Por ejemplo: mvec.find(key) != mvec.cend()es preferible a std::find(mvec.cbegin(), mvec.cend(), key) != mvec.cend().
swalog
113
Como otros han dicho, use el STL findo las find_iffunciones. Pero si usted está buscando en grandes vectores y esto afecta al rendimiento, es posible que desee ordenar su vector y luego usar las binary_search, lower_boundo upper_boundalgoritmos.
¡Buena respuesta! Encontrar siempre es o (n). lower_bound es o (log (n)) si se usa con iteradores de acceso aleatorio.
Stephen Edmonds el
30
Sin embargo, la clasificación es O (nlogn), por lo que vale la pena solo si está haciendo más que búsquedas O (logn).
liori
77
@liori Cierto, depende de tus patrones de uso. Si solo necesita ordenarlo una vez, haga varias búsquedas repetidamente, puede salvarlo.
Brian Neal
1
@Brian Neal, vale la pena ordenar un vector grande si tiene que haber muchas búsquedas de elementos en él. La clasificación será O (nlogn) y O (n) será mejor si uno tiene que encontrar un elemento solo una vez :)
Swapnil B.
47
Use find desde el encabezado del algoritmo de stl. He ilustrado su uso con int type. Puede usar cualquier tipo que desee siempre y cuando pueda comparar la igualdad (sobrecarga == si lo necesita para su clase personalizada).
#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;}
Dependiendo de las necesidades del OP, find_if () también podría ser apropiado. Permite buscar utilizando un predicado arbitrario en lugar de igualdad.
Éric Malenfant
Vaya, vi tu comentario demasiado tarde. La respuesta que di también menciona find_if.
Frank
39
Si su vector no está ordenado, utilice el enfoque sugerido por MSN:
if(std::find(vector.begin(),vector.end(), item)!=vector.end()){// Found the item}
Si su vector está ordenado, use el método binary_search que Brian Neal sugirió:
if(binary_search(vector.begin(),vector.end(), item)){// Found the item}
la búsqueda binaria produce O (log n) en el peor de los casos, que es mucho más eficiente que el primer enfoque. Para usar la búsqueda binaria, puede usar qsort para ordenar el vector primero y garantizar que esté ordenado.
La búsqueda binaria funcionará mejor para contenedores más grandes, pero para contenedores pequeños es probable que una búsqueda lineal simple sea tan rápida o más rápida.
y puede hacer que funcione para listas o vectores mediante el uso de 2 nombres de tipo
Erik Aronesty
@ErikAronesty puede salirse con 1 argumento de plantilla si lo usa value_typedesde el contenedor para el tipo de elemento. He agregado una respuesta como esta.
Martin Broadhurst
13
En C ++ 11 puedes usar any_of. Por ejemplo, si es un vector<string> v;entonces:
Tenga en cuenta que puede salirse con 1 parámetro de plantilla porque puede extraerlo value_typedel Contenedor. Necesita el typenameporque Container::value_typees un nombre dependiente .
Tenga en cuenta que esto a veces es demasiado amplio: funcionaría para std :: set, por ejemplo, pero ofrece un rendimiento terrible en comparación con la función de miembro find (). He encontrado que es mejor agregar una especialización para contenedores con una búsqueda más rápida (set / map, no ordenado_ *)
Andy Krouwel
10
Tenga en cuenta que, si va a hacer muchas búsquedas, hay contenedores STL que son mejores para eso. No sé cuál es su aplicación, pero vale la pena considerar los contenedores asociativos como std :: map.
std :: vector es el contenedor de elección a menos que tenga una razón para otra, y las búsquedas por valor pueden ser tal razón.
Incluso con búsquedas por valor, el vector puede ser una buena opción, siempre que esté ordenado y use binary_search, lower_bound o upper_bound. Si el contenido del contenedor cambia entre búsquedas, el vector no es muy bueno debido a la necesidad de ordenar nuevamente.
Tenga en cuenta que también existe una función find_if , que puede usar si su búsqueda es más compleja, es decir, si no solo está buscando un elemento, sino que, por ejemplo, desea ver si hay un elemento que cumple un cierto condición, por ejemplo, una cadena que comienza con "abc". ( find_ifle daría un iterador que apunta al primer elemento).
#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()}
Puede usar la findfunción, que se encuentra en el stdespacio de nombres, es decir std::find. Pasa la std::findfunción the beginy enditerator del vector que desea buscar, junto con el elemento que está buscando y compara el iterador resultante con el final del vector para ver si coinciden o no.
Esto también es útil para buscar la secuencia de elementos.
#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;}
También hay flexibilidad para pasar algunos algoritmos de búsqueda. Consulte aquí
Personalmente, he usado plantillas en los últimos tiempos para manejar múltiples tipos de contenedores a la vez en lugar de tratar solo con vectores. Encontré un ejemplo similar en línea (no recuerdo dónde), así que el crédito va a quien sea que haya robado esto. Este patrón particular parece manejar también las matrices en bruto.
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);}
Respuestas:
Puedes usar
std::find
desde<algorithm>
:Esto devuelve un bool (
true
si está presente, de lofalse
contrario). Con tu ejemplo:fuente
#include <algorithm>
o de lo contrario podrías obtener errores muy extraños como 'no se puede encontrar la función de coincidencia en el espacio de nombres.find()
todavía no es una función miembrostd::vector
, como cabría esperar? Me pregunto si esto es de alguna manera una consecuencia de la plantilla.std::vector<>::find()
no daría ninguna ventaja, ni es necesaria, por lo tanto, no, no debería ser miembro. Ver también en.wikipedia.org/wiki/Coupling_%28computer_programming%29mvec.find(key) != mvec.cend()
es preferible astd::find(mvec.cbegin(), mvec.cend(), key) != mvec.cend()
.Como otros han dicho, use el STL
find
o lasfind_if
funciones. Pero si usted está buscando en grandes vectores y esto afecta al rendimiento, es posible que desee ordenar su vector y luego usar lasbinary_search
,lower_bound
oupper_bound
algoritmos.fuente
Use find desde el encabezado del algoritmo de stl. He ilustrado su uso con int type. Puede usar cualquier tipo que desee siempre y cuando pueda comparar la igualdad (sobrecarga == si lo necesita para su clase personalizada).
fuente
Si su vector no está ordenado, utilice el enfoque sugerido por MSN:
Si su vector está ordenado, use el método binary_search que Brian Neal sugirió:
la búsqueda binaria produce O (log n) en el peor de los casos, que es mucho más eficiente que el primer enfoque. Para usar la búsqueda binaria, puede usar qsort para ordenar el vector primero y garantizar que esté ordenado.
fuente
std::sort
?qsort
es muy ineficiente en vectores ... ver: stackoverflow.com/questions/12308243/…Yo uso algo como esto ...
... de esa manera es realmente claro y legible. (Obviamente, puede reutilizar la plantilla en varios lugares).
fuente
value_type
desde el contenedor para el tipo de elemento. He agregado una respuesta como esta.En C ++ 11 puedes usar
any_of
. Por ejemplo, si es unvector<string> v;
entonces:Alternativamente, use una lambda:
fuente
bind1st
ybind2nd
están en desuso desde C ++ 11 y se eliminan por completo en C ++ 17. Usebind
conplaceholders
y / o lambdas en su lugar.Aquí hay una función que funcionará para cualquier contenedor:
Tenga en cuenta que puede salirse con 1 parámetro de plantilla porque puede extraerlo
value_type
del Contenedor. Necesita eltypename
porqueContainer::value_type
es un nombre dependiente .fuente
Tenga en cuenta que, si va a hacer muchas búsquedas, hay contenedores STL que son mejores para eso. No sé cuál es su aplicación, pero vale la pena considerar los contenedores asociativos como std :: map.
std :: vector es el contenedor de elección a menos que tenga una razón para otra, y las búsquedas por valor pueden ser tal razón.
fuente
Use la función de búsqueda STL .
Tenga en cuenta que también existe una función find_if , que puede usar si su búsqueda es más compleja, es decir, si no solo está buscando un elemento, sino que, por ejemplo, desea ver si hay un elemento que cumple un cierto condición, por ejemplo, una cadena que comienza con "abc". (
find_if
le daría un iterador que apunta al primer elemento).fuente
Con boost puedes usar
any_of_equal
:fuente
Puedes probar este código:
fuente
Puede usar la
find
función, que se encuentra en elstd
espacio de nombres, es decirstd::find
. Pasa lastd::find
función thebegin
yend
iterator del vector que desea buscar, junto con el elemento que está buscando y compara el iterador resultante con el final del vector para ver si coinciden o no.También puede desreferenciar ese iterador y usarlo de manera normal, como cualquier otro iterador.
fuente
Puedes usar count también. Devolverá el número de elementos presentes en un vector.
fuente
find
es más rápido quecount
, porque no sigue contando después del primer partido.Si quieres encontrar una cadena en un vector:
fuente
Otra muestra usando operadores C ++.
fuente
fuente
(C ++ 17 y superior):
puede usar
std::search
tambiénEsto también es útil para buscar la secuencia de elementos.
También hay flexibilidad para pasar algunos algoritmos de búsqueda. Consulte aquí
https://en.cppreference.com/w/cpp/algorithm/search
fuente
Personalmente, he usado plantillas en los últimos tiempos para manejar múltiples tipos de contenedores a la vez en lugar de tratar solo con vectores. Encontré un ejemplo similar en línea (no recuerdo dónde), así que el crédito va a quien sea que haya robado esto. Este patrón particular parece manejar también las matrices en bruto.
fuente
Usar Newton C ++ es más fácil, auto documentado y más rápido que con std :: find debido a que devuelve un bool directamente.
Creo que es obvio lo que hacen las funciones.
fuente