wyszukiwanie w wektorze jest bardzo wolne, ponieważ musisz patrzeć na każdy element wektora, więc rozważ użycie mapy, jeśli wykonujesz wiele
odnośników
7
@naumcho: Jeśli wektor jest posortowany, zawsze następuje wyszukiwanie binarne, jak podano poniżej. Dzięki temu jest tak szybki jak mapa, a jeśli przechowujesz tylko wartości (a nie mapy kluczy / wartości), zużyje o wiele mniej pamięci.
Adam Hawes
4
mapy z pewnością nie są najlepszym wyborem, ale użycie zestawu może być przydatne. Jeśli potrzebujesz czasu wyszukiwania O (1), najlepszym rozwiązaniem jest hash_set.
#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()
Zwraca bool ( truejeśli jest obecny, w falseprzeciwnym razie). Na przykład:
Nie rozumiem, w jaki sposób count () może być szybszy niż find (), ponieważ find () zatrzymuje się natychmiast po znalezieniu jednego elementu, podczas gdy count () zawsze musi skanować całą sekwencję.
Éric Malenfant
114
Nie zapomnij, #include <algorithm>bo mogą się pojawić bardzo dziwne błędy, takie jak „nie można znaleźć pasującej funkcji w przestrzeni nazw std”
rustyx
80
Czy nikomu nie przeszkadzało, że pomimo tego, że STL jest „obiektowe”, .find()wciąż nie jest funkcją członka std::vector, jak można się spodziewać? Zastanawiam się, czy jest to w jakiś sposób konsekwencja szablonowania.
bobobobo,
71
@bobobobo: OOP nie ma nic wspólnego z członkami vs. osobami niebędącymi członkami. I istnieje szeroko rozpowszechniona szkoła myślenia, że jeśli coś nie musi być członkiem lub gdy nie daje żadnej korzyści, gdy jest wdrażane jako członek, to nie powinno być członkiem; std::vector<>::find()nie dałoby żadnej korzyści, ani też nie jest potrzebne, dlatego nie, nie powinien być członkiem. Zobacz także en.wikipedia.org/wiki/Coupling_%28computer_programming%29
Sebastian Mach
36
@phresnel Argumentowałbym, że „jeśli nie daje żadnej korzyści, gdy jest implementowany jako członek”, jest w tym przypadku fałszywe. Zaletą jest uproszczony i bardziej przejrzysty interfejs. Na przykład: mvec.find(key) != mvec.cend()lepiej niż std::find(mvec.cbegin(), mvec.cend(), key) != mvec.cend().
swalog
113
Jak powiedzieli inni, użyj STL findlub find_iffunkcji. Ale jeśli szukasz w bardzo dużych wektorów i wydajność to wpływ, może chcesz uporządkować swoje wektor a następnie użyć binary_search, lower_boundlub upper_boundalgorytmów.
Dobra odpowiedź! Znajdź to zawsze o (n). dolna wartość to o (log (n)), jeśli jest używane z iteratorami o swobodnym dostępie.
Stephen Edmonds
30
Sortowanie odbywa się jednak w trybie O (nlogn), więc warto je wykonywać tylko wtedy, gdy wykonujesz więcej niż wyszukiwania O (logn).
liori
7
@liori Prawda, że zależy to od twoich wzorców użytkowania. Jeśli musisz go posortować tylko raz, to wielokrotnie wykonuj wiele wyszukiwań, aby cię uratować.
Brian Neal,
1
@Brian Neal, sortowanie dużego wektora jest warte, jeśli musi być na nim wiele wyszukiwań elementów. Sortowanie będzie O (nlogn), a O (n) będzie lepsze, jeśli trzeba znaleźć element tylko raz :)
Swapnil B.
47
Użyj find z nagłówka algorytmu stl. Zilustrowałem jego użycie typem int. Możesz użyć dowolnego typu, pod warunkiem, że możesz porównać dla równości (przeciążenie ==, jeśli potrzebujesz dla swojej klasy niestandardowej).
#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;}
W zależności od potrzeb PO odpowiednia może być również find_if (). Umożliwia wyszukiwanie przy użyciu dowolnego predykatu zamiast równości.
Éric Malenfant,
Ups, zobaczyłem twój komentarz za późno. W udzielonej przeze mnie odpowiedzi wspomina się także o find_if.
Frank
39
Jeśli twój wektor nie jest uporządkowany, użyj sugerowanego przez MSN podejścia:
if(std::find(vector.begin(),vector.end(), item)!=vector.end()){// Found the item}
Jeśli twój wektor jest uporządkowany, użyj metody binary_search Brian Neal zasugerował:
if(binary_search(vector.begin(),vector.end(), item)){// Found the item}
wyszukiwanie binarne daje wydajność O (log n) w najgorszym przypadku, która jest znacznie wydajniejsza niż pierwsze podejście. Aby użyć wyszukiwania binarnego, możesz użyć qsort, aby najpierw posortować wektor, aby upewnić się, że jest on uporządkowany.
Wyszukiwanie binarne będzie działać lepiej w przypadku większych kontenerów, ale w przypadku małych kontenerów proste wyszukiwanie liniowe może być równie szybkie lub szybsze.
Pamiętaj, że możesz uciec z 1 parametrem szablonu, ponieważ możesz wyodrębnić go value_typez kontenera. Potrzebujesz, typenameponieważ ponieważ Container::value_typejest to nazwa zależna .
Zauważ, że czasami jest to trochę za szerokie - działałoby to na przykład dla std :: set, ale dawało straszną wydajność w porównaniu z funkcją członka find (). Uważam, że najlepiej jest dodać specjalizację dla kontenerów z szybszym wyszukiwaniem (set / map, unordered_ *)
Andy Krouwel,
10
Pamiętaj, że jeśli będziesz przeprowadzać wiele przeglądów, lepiej nadają się pojemniki STL. Nie wiem, jaka jest twoja aplikacja, ale warto rozważyć kontenery asocjacyjne, takie jak std :: map.
std :: vector jest pojemnikiem z wyboru, chyba że masz powód innego, a wyszukiwania według wartości mogą być takim powodem.
Nawet w przypadku wyszukiwania według wartości wektor może być dobrym wyborem, o ile jest on posortowany i używasz wyszukiwania binarnego, dolnego lub górnego. Jeśli zawartość kontenera zmienia się między przeglądami, wektor nie jest zbyt dobry z powodu konieczności ponownego sortowania.
Należy pamiętać, że istnieje również funkcja find_if , z której można skorzystać, jeśli wyszukiwanie jest bardziej złożone, tj. Jeśli nie szukasz tylko elementu, ale na przykład chcesz sprawdzić, czy element spełnia określony warunek, na przykład ciąg rozpoczynający się od „abc”. ( find_ifdałby ci iterator, który wskazuje na pierwszy taki element).
#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()}
Możesz użyć findfunkcji znajdującej się w stdprzestrzeni nazw, tj std::find. Przekazujesz std::findfunkcję begini enditerator z wektora, który chcesz wyszukać, wraz z szukanym elementem i porównujesz wynikowy iterator z końcem wektora, aby sprawdzić, czy są one zgodne.
Jest to również przydatne do wyszukiwania sekwencji elementów.
#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;}
Istnieje również elastyczność przekazywania niektórych algorytmów wyszukiwania. Zobacz tutaj.
Ostatnio osobiście używałem szablonów do obsługi wielu rodzajów pojemników jednocześnie, zamiast zajmować się tylko wektorami. Znalazłem podobny przykład online (nie pamiętam, gdzie), więc uznanie należy się każdemu, z kogo go ukradłem. Ten szczególny wzór wydaje się również obsługiwać surowe tablice.
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);}
Odpowiedzi:
Możesz używać
std::find
z<algorithm>
:Zwraca bool (
true
jeśli jest obecny, wfalse
przeciwnym razie). Na przykład:źródło
#include <algorithm>
bo mogą się pojawić bardzo dziwne błędy, takie jak „nie można znaleźć pasującej funkcji w przestrzeni nazw std”.find()
wciąż nie jest funkcją członkastd::vector
, jak można się spodziewać? Zastanawiam się, czy jest to w jakiś sposób konsekwencja szablonowania.std::vector<>::find()
nie dałoby żadnej korzyści, ani też nie jest potrzebne, dlatego nie, nie powinien być członkiem. Zobacz także en.wikipedia.org/wiki/Coupling_%28computer_programming%29mvec.find(key) != mvec.cend()
lepiej niżstd::find(mvec.cbegin(), mvec.cend(), key) != mvec.cend()
.Jak powiedzieli inni, użyj STL
find
lubfind_if
funkcji. Ale jeśli szukasz w bardzo dużych wektorów i wydajność to wpływ, może chcesz uporządkować swoje wektor a następnie użyćbinary_search
,lower_bound
lubupper_bound
algorytmów.źródło
Użyj find z nagłówka algorytmu stl. Zilustrowałem jego użycie typem int. Możesz użyć dowolnego typu, pod warunkiem, że możesz porównać dla równości (przeciążenie ==, jeśli potrzebujesz dla swojej klasy niestandardowej).
źródło
Jeśli twój wektor nie jest uporządkowany, użyj sugerowanego przez MSN podejścia:
Jeśli twój wektor jest uporządkowany, użyj metody binary_search Brian Neal zasugerował:
wyszukiwanie binarne daje wydajność O (log n) w najgorszym przypadku, która jest znacznie wydajniejsza niż pierwsze podejście. Aby użyć wyszukiwania binarnego, możesz użyć qsort, aby najpierw posortować wektor, aby upewnić się, że jest on uporządkowany.
źródło
std::sort
?qsort
jest bardzo nieefektywny w przypadku wektorów .... patrz: stackoverflow.com/questions/12308243/...Używam czegoś takiego ...
... w ten sposób jest to właściwie jasne i czytelne. (Oczywiście możesz ponownie użyć szablonu w wielu miejscach).
źródło
value_type
z kontenera dla typu elementu. Dodałem taką odpowiedź.W C ++ 11 możesz używać
any_of
. Na przykład jeśli jest tovector<string> v;
wtedy:Alternatywnie użyj lambda:
źródło
bind1st
ibind2nd
są przestarzałe od C ++ 11 i całkowicie usunięte w C ++ 17. Zamiast tego używajbind
zplaceholders
i / lub lambdas.Oto funkcja, która będzie działać dla każdego kontenera:
Pamiętaj, że możesz uciec z 1 parametrem szablonu, ponieważ możesz wyodrębnić go
value_type
z kontenera. Potrzebujesz,typename
ponieważ ponieważContainer::value_type
jest to nazwa zależna .źródło
Pamiętaj, że jeśli będziesz przeprowadzać wiele przeglądów, lepiej nadają się pojemniki STL. Nie wiem, jaka jest twoja aplikacja, ale warto rozważyć kontenery asocjacyjne, takie jak std :: map.
std :: vector jest pojemnikiem z wyboru, chyba że masz powód innego, a wyszukiwania według wartości mogą być takim powodem.
źródło
Użyj funkcji wyszukiwania STL .
Należy pamiętać, że istnieje również funkcja find_if , z której można skorzystać, jeśli wyszukiwanie jest bardziej złożone, tj. Jeśli nie szukasz tylko elementu, ale na przykład chcesz sprawdzić, czy element spełnia określony warunek, na przykład ciąg rozpoczynający się od „abc”. (
find_if
dałby ci iterator, który wskazuje na pierwszy taki element).źródło
Dzięki doładowaniu możesz użyć
any_of_equal
:źródło
Możesz wypróbować ten kod:
źródło
Możesz użyć
find
funkcji znajdującej się wstd
przestrzeni nazw, tjstd::find
. Przekazujeszstd::find
funkcjębegin
iend
iterator z wektora, który chcesz wyszukać, wraz z szukanym elementem i porównujesz wynikowy iterator z końcem wektora, aby sprawdzić, czy są one zgodne.Możesz także wyłuskać ten iterator i używać go normalnie, jak każdego innego iteratora.
źródło
Możesz też użyć count. Zwróci liczbę elementów obecnych w wektorze.
źródło
find
jest szybszy niżcount
, ponieważ nie liczy się po pierwszym meczu.Jeśli chcesz znaleźć ciąg w wektorze:
źródło
Kolejny przykład wykorzystujący operatory C ++.
źródło
źródło
(C ++ 17 i wyżej):
można
std::search
również użyćJest to również przydatne do wyszukiwania sekwencji elementów.
Istnieje również elastyczność przekazywania niektórych algorytmów wyszukiwania. Zobacz tutaj.
https://en.cppreference.com/w/cpp/algorithm/search
źródło
Ostatnio osobiście używałem szablonów do obsługi wielu rodzajów pojemników jednocześnie, zamiast zajmować się tylko wektorami. Znalazłem podobny przykład online (nie pamiętam, gdzie), więc uznanie należy się każdemu, z kogo go ukradłem. Ten szczególny wzór wydaje się również obsługiwać surowe tablice.
źródło
Korzystanie z Newton C ++ jest łatwiejsze, samo-udokumentowane i szybsze niż w przypadku std :: find, ponieważ zwraca bool bezpośrednio.
Myślę, że to oczywiste, co robią te funkcje.
źródło