Wprowadzamy C ++ 0x, unordered_set
który jest dostępny w boost
wielu innych miejscach. Rozumiem, że unordered_set
jest to tabela skrótów ze O(1)
złożonością wyszukiwania. Z drugiej strony set
to nic innego jak drzewo o log(n)
złożoności wyszukiwania. Dlaczego, u licha, ktoś miałby używać set
zamiast unordered_set
? tj. czy jest już taka potrzeba set
?
145
Odpowiedzi:
Kiedy dla kogoś, kto chce iterować elementy zestawu, kolejność ma znaczenie.
źródło
< >
?Nieuporządkowane zestawy muszą płacić za średni czas dostępu O (1) na kilka sposobów:
set
zużywa mniej pamięci niżunordered_set
przechowywanie tej samej liczby elementów.set
mogą być szybsze niż wyszukiwania wunordered_set
.unordered_set
, często są one gwarantowane mieć lepsze najgorszym przypadku zawiłości dlaset
(na przykładinsert
).set
sortuje elementy jest przydatne, jeśli chcesz uzyskać do nich dostęp w kolejności.set
sz<
,<=
,>
i>=
.unordered_set
nie są wymagane do obsługi tych operacji.źródło
<
).Zawsze, gdy wolisz drzewo od tabeli skrótów.
Na przykład tabele skrótów mają w najgorszym przypadku wartość „O (n)”. O (1) to przeciętny przypadek. W najgorszym przypadku drzewa są „O ( log n)”.
źródło
Użyj zestawu, gdy:
Użyj unordered_set, gdy:
Przykłady:
zestaw:
Wejście: 1, 8, 2, 5, 3, 9
Wyjście: 1, 2, 3, 5, 8, 9
Unordered_set:
Wejście: 1, 8, 2, 5, 3, 9
Wyjście: 9 3 1 8 2 5 (może ta kolejność, na którą ma wpływ funkcja skrótu)
Głównie różnica:
Uwaga: (w niektórych przypadkach
set
jest to wygodniejsze) na przykład użycievector
jako kluczaPowodem, dla którego
vector<int>
może być kluczemset
bovector
ręcznymoperator<
.Ale jeśli używasz
unordered_set<vector<int>>
, musisz utworzyć funkcję skrótu dlavector<int>
, ponieważ wektor nie ma funkcji skrótu, więc musisz zdefiniować taką:widać, że w niektórych przypadkach
unordered_set
jest to bardziej skomplikowane.Cytowane głównie z: https://www.geeksforgeeks.org/set-vs-unordered_set-c-stl/ https://stackoverflow.com/a/29855973/6329006
źródło
Ponieważ std :: set jest częścią Standard C ++, a unordered_set nie jest. C ++ 0x NIE jest standardem, podobnie jak Boost. Dla wielu z nas przenośność jest niezbędna, a to oznacza trzymanie się standardów.
źródło
Rozważmy algorytmy linii przebiegu. Algorytmy te całkowicie zawiodłyby w przypadku tablic mieszających, ale działają pięknie ze zrównoważonymi drzewami. Aby dać ci konkretny przykład algorytmu linii losowania, rozważ algorytm fortuny. http://en.wikipedia.org/wiki/Fortune%27s_algorithm
źródło
Jeszcze jedno, oprócz tego, o czym wspomniały już inne osoby. A oczekiwane zamortyzowany złożoność do wprowadzania elementu do unordered_set O (1), co jakiś czas, a następnie będzie się O (N), ponieważ wymaga mieszającego stołowych restrukturyzowany (liczby segmentów musi zmienić) - nawet „dobra” funkcja skrótu. Podobnie jak wstawianie elementu do wektora wymaga od czasu do czasu O (n), ponieważ podstawowa tablica musi zostać ponownie przydzielona.
Wstawienie do zestawu zawsze zajmuje najwyżej O (log n). Może to być preferowane w niektórych aplikacjach.
źródło
Przepraszam, jeszcze jedna rzecz, na którą warto zwrócić uwagę w przypadku posortowanej nieruchomości:
Jeśli chcesz zakres danych w kontenerze, na przykład: Zapisałeś czas w zestawie , a chcesz czas od 01.01.2013 do 01.01.2014.
Dla unordered_set jest to niemożliwe.
Oczywiście ten przykład byłby bardziej przekonujący dla przypadków użycia między mapą a unordered_map .
źródło
g++
6.4 Stdlibc ++ benchmark uporządkowanego a nieuporządkowanego zestawuTestowałem tę dominującą implementację Linux C ++, aby zobaczyć różnicę:
Pełne szczegóły i analiza testu porównawczego zostały podane pod adresem: Jaka jest podstawowa struktura danych STL w C ++? i nie będę ich tutaj powtarzał.
„BST” oznacza „przetestowano z,
std::set
a„ mapa skrótów ”oznacza„ przetestowano zstd::unordered_set
. „Sterta” jest, dlastd::priority_queue
której przeanalizowałem: Heap vs Binary Search Tree (BST)Krótkie podsumowanie:
wykres wyraźnie pokazuje, że w tych warunkach wstawianie haszmap było zawsze dużo szybsze, gdy jest więcej niż 100 tys. elementów, a różnica rośnie wraz ze wzrostem liczby elementów
Koszt tego przyspieszenia polega na tym, że nie jesteś w stanie efektywnie poruszać się po kolei.
krzywe wyraźnie sugerują, że zamówiony produkt
std::set
jest oparty na BST i oparty nastd::unordered_set
hashmap. W odpowiedzi referencyjnej dodatkowo potwierdziłem, że przez krok GDB debugowanie kodu.Podobne pytanie dla
map
vsunordered_map
: Czy jest jakaś przewaga używania map nad unordered_map w przypadku trywialnych kluczy?źródło
Z drugiej strony, powiedziałbym, że wygodnie jest mieć rzeczy w związku, jeśli chcesz przekonwertować je na inny format.
Możliwe jest również, że chociaż dostęp do niego jest szybszy, czas potrzebny na zbudowanie indeksu lub pamięci używanej podczas tworzenia i / lub uzyskiwania dostępu do niego jest dłuższy.
źródło
Jeśli chcesz, aby rzeczy były posortowane, użyj set zamiast unordered_set. unordered_set jest używany nad zestawem, gdy kolejność przechowywania nie ma znaczenia.
źródło
Chociaż ta odpowiedź może być opóźniona o 10 lat, warto na to zwrócić uwagę
std::unordered_set
ma również wady bezpieczeństwa.Jeśli funkcja skrótu jest przewidywalna (jest to zwykle przypadek, chyba że stosuje środki zaradcze, takie jak losowa sól), atakujący mogą ręcznie tworzyć dane, które powodują kolizje hash i powodują, że wszystkie wstawienia i wyszukiwania zajmują O (n) czasu .
Można to wykorzystać do bardzo skutecznych i eleganckich ataków typu „odmowa usługi”.
Wiele (większość?) Implementacji języków, które wewnętrznie używają map skrótów, napotkało to:
źródło