Obecnie mam, std::map<std::string,int>
który przechowuje wartość całkowitą do unikalnego identyfikatora ciągu i wyszukuję ciąg. Robi głównie to, co chcę, z wyjątkiem tego, że nie śledzi zamówienia reklamowego. Więc kiedy iteruję mapę, aby wydrukować wartości, są one sortowane według ciągu; ale chcę, aby były sortowane zgodnie z kolejnością (pierwszego) wstawienia.
Zastanawiałem się nad użyciem vector<pair<string,int>>
zamiast tego, ale muszę poszukać ciągu i zwiększyć wartości całkowite około 10 000 000 razy, więc nie wiem, czy a std::vector
będzie znacznie wolniejsze.
Czy istnieje sposób użycia std::map
lub czy jest inny std
pojemnik, który lepiej odpowiada moim potrzebom?
[Jestem na GCC 3.4 i prawdopodobnie mam nie więcej niż 50 par wartości w moim std::map
].
Dzięki.
źródło
Odpowiedzi:
Jeśli masz tylko 50 wartości w std :: map, możesz skopiować je do std :: vector przed wydrukowaniem i posortować przez std :: sort za pomocą odpowiedniego funktora.
Lub możesz użyć boost :: multi_index . Pozwala na użycie kilku indeksów. W twoim przypadku może to wyglądać następująco:
źródło
Możesz połączyć a
std::vector
zstd::tr1::unordered_map
(tablicą skrótów). Oto link do dokumentacji Boost dlaunordered_map
. Możesz użyć wektora, aby śledzić kolejność reklam, a tabelę skrótów do częstych wyszukiwań. Jeśli wykonujesz setki tysięcy wyszukiwań, różnica między wyszukiwaniem O (log n) dlastd::map
i O (1) dla tabeli skrótów może być znacząca.źródło
std::map
na pracę tak, jak powinna (tj. Sortuje się podczas wstawiania) i ma szybki czas wykonania. (Przeczytałem to po napisaniu mojej wersji, w której użyłem std :: list!)Zachowaj paralelę
list<string> insertionOrder
.Kiedy nadejdzie czas drukowania, powtórz listę i przeszukaj mapę .
źródło
std::string_view
jako kluczy mapy odnoszących się dostd::string
nainsertionOrder
liście. Pozwala to uniknąć kopiowania, ale musisz uważać, abyinsertionOrder
elementy przeżywały klucze na mapie, które się do nich odnoszą.Tessil posiada bardzo fajną implementację uporządkowanej mapy (i zestawu) jaką jest licencja MIT. Możesz go znaleźć tutaj: Mapa-uporządkowana
Przykład mapy
źródło
Jeśli potrzebujesz obu strategii wyszukiwania, otrzymasz dwa kontenery. Możesz użyć a
vector
ze swoimi rzeczywistymi wartościamiint
i umieścićmap< string, vector< T >::difference_type>
obok niego, zwracając indeks do wektora.Aby to wszystko zakończyć, możesz ująć oba w jednej klasie.
Ale uważam, że boost ma pojemnik z wieloma indeksami.
źródło
To, czego chcesz (bez uciekania się do Boost), to coś, co nazywam „uporządkowanym hashem”, który jest zasadniczo połączeniem skrótu i połączonej listy z kluczami ciągów lub liczb całkowitych (lub obu jednocześnie). Uporządkowany hash zachowuje kolejność elementów podczas iteracji z absolutną wydajnością hasha.
Tworzyłem stosunkowo nową bibliotekę fragmentów kodu C ++, która wypełnia to, co uważam za dziury w języku C ++ dla programistów bibliotek C ++. Przejdź tutaj:
https://github.com/cubiclesoft/cross-platform-cpp
Chwycić:
Jeśli dane kontrolowane przez użytkownika zostaną umieszczone w haszu, możesz również chcieć:
Wywołaj to:
Natknąłem się na ten wątek SO podczas mojej fazy badań, aby sprawdzić, czy coś takiego jak OrderedHash już istniało bez konieczności opuszczania ogromnej biblioteki. Byłem rozczarowany. Więc napisałem własne. A teraz się tym podzieliłem.
źródło
Nie możesz tego zrobić z mapą, ale możesz użyć dwóch oddzielnych struktur - mapy i wektora i utrzymywać je zsynchronizowane - to znaczy, gdy usuwasz z mapy, znajdujesz i usuwasz element z wektora. Lub możesz utworzyć
map<string, pair<int,int>>
- i zapisać w swojej parze rozmiar () mapy po wstawieniu do pozycji rekordu, wraz z wartością int, a następnie podczas drukowania użyj elementu członkowskiego pozycji do sortowania.źródło
Innym sposobem zaimplementowania tego jest
map
użycie zamiastvector
. Pokażę Ci to podejście i omówię różnice:Po prostu stwórz klasę, która ma dwie mapy za kulisami.
Następnie możesz udostępnić iterator iteratorowi
data_
w odpowiedniej kolejności. Sposób, w jaki to robisz, to iteracjainsertion_order_
, a dla każdego elementu uzyskanego z tej iteracji wykonaj wyszukiwanie wdata_
z wartością zinsertion_order_
Możesz użyć bardziej wydajnego
hash_map
dla insertion_order, ponieważ nie zależy ci na bezpośrednim iterowaniuinsertion_order_
.Aby zrobić wstawki, możesz skorzystać z następującej metody:
Istnieje wiele sposobów na ulepszenie projektu i martwienie się o wydajność, ale jest to dobry szkielet, aby rozpocząć samodzielne wdrażanie tej funkcji. Możesz zrobić to na podstawie szablonu i możesz faktycznie przechowywać pary jako wartości w data_, abyś mógł łatwo odwołać się do wpisu w insertion_order_. Ale zostawię te kwestie projektowe jako ćwiczenie :-).
Aktualizacja : przypuszczam, że powinienem powiedzieć coś o efektywności wykorzystania mapy vs. wektor dla insertion_order_
Może jeśli nie zamierzasz tak często używać usuwania, powinieneś użyć podejścia wektorowego. Podejście do mapy byłoby lepsze, gdybyś obsługiwał inną kolejność (np. Priorytet) zamiast zamówienia reklamowego.
źródło
Oto rozwiązanie, które wymaga tylko standardowej biblioteki szablonów bez użycia multiindeksu boost:
Możesz użyć
std::map<std::string,int>;
ivector <data>;
gdzie na mapie przechowywać indeks lokalizacji danych w wektorze, a wektor przechowuje dane w kolejności wstawiania. Tutaj dostęp do danych ma złożoność O (log n). wyświetlanie danych w kolejności reklamowej ma złożoność O (n). wstawianie danych ma złożoność O (log n).Na przykład:
źródło
Jest to w pewnym stopniu związane z odpowiedzią Faisals. Możesz po prostu utworzyć klasę opakowującą wokół mapy i wektora i łatwo je zsynchronizować. Odpowiednia enkapsulacja pozwoli ci kontrolować metodę dostępu, a tym samym, którego kontenera użyć ... wektora czy mapy. Pozwala to uniknąć używania Boost lub czegoś podobnego.
źródło
Należy wziąć pod uwagę niewielką liczbę używanych elementów danych. Możliwe, że szybsze będzie użycie samego wektora. Na mapie występuje pewne obciążenie, które może spowodować, że wyszukiwanie w małych zestawach danych będzie droższe niż w przypadku prostszego wektora. Tak więc, jeśli wiesz, że zawsze będziesz używać tej samej liczby elementów, zrób kilka testów porównawczych i sprawdź, czy wydajność mapy i wektora jest taka, jak myślisz. Może się okazać, że wyszukiwanie w wektorze zawierającym tylko 50 elementów jest zbliżone do mapy.
źródło
// Powinien być taki jak ten mężczyzna!
// Utrzymuje to złożoność wstawiania O (logN), a usuwanie to również O (logN).
źródło
Używaj
boost::multi_index
z indeksami map i list.źródło
Mapa pary (str, int) i statyczna wartość int, która zwiększa się przy wywołaniach wstawiania, indeksuje pary danych. Być może umieścić strukturę, która może zwrócić statyczną wartość int z elementem index ()?
źródło