O C ++ 0x está apresentando o unordered_set
que está disponível em boost
muitos outros lugares. O que eu entendo é que unordered_set
é uma tabela de hash com O(1)
complexidade de pesquisa. Por outro lado, set
nada mais é do que uma árvore com log(n)
complexidade de pesquisa. Por que diabos alguém usaria em set
vez de unordered_set
? ou seja, é necessário set
mais?
145
Respostas:
Quando, para alguém que deseja iterar nos itens do conjunto, o pedido é importante.
fonte
< >
?Os conjuntos não ordenados precisam pagar pelo tempo médio de acesso de O (1) de algumas maneiras:
set
usa menos memória queunordered_set
para armazenar o mesmo número de elementos.set
podem ser mais rápidas que as pesquisas em umunordered_set
.unordered_set
, muitas vezes são garantidos para ter melhores piores complexidades de casos paraset
(por exemploinsert
).set
classifica os elementos é útil se você deseja acessá-los em ordem.set
s com<
,<=
,>
e>=
.unordered_set
s não são necessários para suportar essas operações.fonte
<
).Sempre que você prefere uma árvore a uma tabela de hash.
Por exemplo, tabelas de hash são "O (n)" na pior das hipóteses. O (1) é o caso médio. As árvores são "O ( log n)" na pior das hipóteses.
fonte
Use set quando:
Use unordered_set quando:
Exemplos:
conjunto:
Entrada: 1, 8, 2, 5, 3, 9
Saída: 1, 2, 3, 5, 8, 9
Unordered_set:
Entrada: 1, 8, 2, 5, 3, 9
Saída: 9 3 1 8 2 5 (talvez esta ordem, influenciada pela função hash)
Principalmente diferença:
Nota: (em alguns casos,
set
é mais conveniente), por exemplo, usandovector
como chaveA razão pela qual
vector<int>
pode ser a chave,set
porquevector
substituioperator<
.Mas se você usar,
unordered_set<vector<int>>
precisará criar uma função de hash paravector<int>
, porque o vetor não tem uma função de hash, então você deve definir uma como:você pode ver que em alguns casos
unordered_set
é mais complicado.Citado principalmente em: https://www.geeksforgeeks.org/set-vs-unordered_set-c-stl/ https://stackoverflow.com/a/29855973/6329006
fonte
Porque std :: set faz parte do C ++ padrão e unordered_set não. C ++ 0x NÃO é um padrão, nem o Boost. Para muitos de nós, a portabilidade é essencial, e isso significa manter o padrão.
fonte
Considere algoritmos de varredura. Esses algoritmos falhariam totalmente com tabelas de hash, mas funcionam lindamente com árvores balanceadas. Para dar um exemplo concreto de um algoritmo de varredura, considere o algoritmo da fortuna. http://en.wikipedia.org/wiki/Fortune%27s_algorithm
fonte
Mais uma coisa, além do que outras pessoas já mencionaram. Embora a complexidade amortizada esperada para inserir um elemento em um conjunto não ordenado seja O (1), de vez em quando ele será necessário O (n) porque a tabela de hash precisa ser reestruturada (o número de buckets precisa mudar) - mesmo com uma função hash 'boa'. Assim como a inserção de um elemento em um vetor recebe O (n) de vez em quando, porque a matriz subjacente precisa ser realocada.
A inserção em um conjunto sempre leva no máximo O (log n). Isso pode ser preferível em alguns aplicativos.
fonte
Perdoe-me, mais uma coisa que vale a pena notar sobre a propriedade classificada:
Se você deseja um intervalo de dados no contêiner, por exemplo: Você armazenou o tempo no conjunto e deseja o tempo de 01-01-2013 a 01-01-2014.
Para unordered_set , é impossível.
Obviamente, este exemplo seria mais convincente para casos de uso entre map e unordered_map .
fonte
g++
6.4 stdlibc ++ ordenado vs benchmark de conjunto não ordenadoComparei essa implementação dominante do Linux C ++ para ver a diferença:
Os detalhes e análises completos do benchmark foram fornecidos em: Qual é a estrutura de dados subjacente de um conjunto de STL em C ++?e não vou repeti-los aqui.
"BST" significa "testado com
std::set
e" mapa de hash "significa" testado comstd::unordered_set
. "Heap" é para ostd::priority_queue
qual eu analisei em: Heap vs Binary Search Tree (BST)Como um resumo rápido:
o gráfico mostra claramente que, nessas condições, a inserção de hashmap sempre foi muito mais rápida quando há mais de 100 mil itens, e a diferença aumenta à medida que o número de itens aumenta
O custo desse aumento de velocidade é que você não é capaz de percorrer com eficiência em ordem.
as curvas sugerem claramente que o pedido
std::set
é baseado no BST e ostd::unordered_set
hashmap. Na resposta de referência, confirmei ainda que, por meio do GDB, depure o código.Pergunta semelhante para
map
vsunordered_map
: Existe alguma vantagem em usar o mapa sobre unordered_map no caso de chaves triviais?fonte
Por outro lado, eu diria que é conveniente ter coisas em um relacionamento se você deseja convertê-lo em um formato diferente.
Também é possível que, embora o acesso seja mais rápido, o tempo para criar o índice ou a memória usada ao criar e / ou acessá-lo seja maior.
fonte
Se você deseja que as coisas sejam classificadas, use set em vez de unordered_set. unordered_set é usado sobre o conjunto quando o pedido armazenado não importa.
fonte
Embora essa resposta possa demorar 10 anos, vale ressaltar que
std::unordered_set
também tem desvantagens na segurança.Se a função hash for previsível (normalmente, a menos que aplique medidas contrárias, como um sal aleatório), os atacantes podem criar dados manualmente que produzem colisões de hash e fazem com que todas as inserções e pesquisas levem tempo O (n) .
Isso pode ser usado para ataques de negação de serviço muito eficientes e elegantes.
Muitas (a maioria?) Implementações de idiomas que empregam internamente mapas de hash se deparam com isso:
fonte