Atualmente, tenho um std::map<std::string,int>
que armazena um valor inteiro em um identificador de string exclusivo e procuro na string. Ele faz principalmente o que eu desejo, exceto que não acompanha o pedido de inserção. Então, quando eu itero o mapa para imprimir os valores, eles são classificados de acordo com a string; mas eu quero que eles sejam classificados de acordo com a ordem de (primeira) inserção.
Pensei em usar um vector<pair<string,int>>
, mas preciso pesquisar a string e incrementar os valores inteiros cerca de 10.000.000 vezes, então não sei se a std::vector
será significativamente mais lento.
Existe uma maneira de usar std::map
ou existe outro std
container que melhor se adapte às minhas necessidades?
[Estou no GCC 3.4 e provavelmente não tenho mais do que 50 pares de valores no meu std::map
].
Obrigado.
fonte
Respostas:
Se você tiver apenas 50 valores em std :: map, poderá copiá-los para std :: vector antes de imprimir e classificar por meio de std :: sort usando o functor apropriado.
Ou você pode usar boost :: multi_index . Permite usar vários índices. No seu caso, poderia ser o seguinte:
fonte
Você pode combinar a
std::vector
com astd::tr1::unordered_map
(uma tabela hash). Aqui está um link para a documentação do Boost paraunordered_map
. Você pode usar o vetor para controlar a ordem de inserção e a tabela hash para fazer pesquisas frequentes. Se você estiver fazendo centenas de milhares de pesquisas, a diferença entre O (log n) pesquisa parastd::map
e O (1) para uma tabela hash pode ser significativa.fonte
std::map
trabalhar como deveria (ou seja, ordenando-se conforme você insere), e tem um tempo de execução rápido. (Eu li isso depois de escrever minha versão, onde usei std :: list!)Mantenha um paralelo
list<string> insertionOrder
.Quando chegar a hora de imprimir, itere na lista e faça pesquisas no mapa .
fonte
std::string_view
para as chaves do mapa referentes aostd::string
nainsertionOrder
lista. Isso evita a cópia, mas você precisa ter cuidado para que osinsertionOrder
elementos sobrevivam às chaves no mapa que se referem a eles.Tessil tem uma implementação muito boa de mapa ordenado (e conjunto) que é uma licença do MIT. Você pode encontrá-lo aqui: mapa-ordenado
Exemplo de mapa
fonte
Se você precisar das duas estratégias de pesquisa, terá dois contêineres. Você pode usar um
vector
com seu (int
s) valor ( es) real ( is) e colocar ummap< string, vector< T >::difference_type>
próximo a ele, retornando o índice para o vetor.Para completar tudo isso, você pode encapsular ambos em uma classe.
Mas acredito que boost tem um contêiner com vários índices.
fonte
O que você deseja (sem recorrer ao Boost) é o que chamo de "hash ordenado", que é essencialmente um mashup de um hash e uma lista vinculada com strings ou chaves inteiras (ou ambos ao mesmo tempo). Um hash ordenado mantém a ordem dos elementos durante a iteração com o desempenho absoluto de um hash.
Tenho reunido uma biblioteca de snippet C ++ relativamente nova que preenche o que considero lacunas na linguagem C ++ para desenvolvedores de bibliotecas C ++. Vá aqui:
https://github.com/cubiclesoft/cross-platform-cpp
Agarrar:
Se os dados controlados pelo usuário forem colocados no hash, você também pode querer:
Invoque-o:
Corri para este segmento SO durante minha fase de pesquisa para ver se algo como OrderedHash já existia sem exigir que eu colocasse em uma biblioteca enorme. Fiquei desapontado. Então eu escrevi meu próprio. E agora eu compartilhei isso.
fonte
Você não pode fazer isso com um mapa, mas pode usar duas estruturas separadas - o mapa e o vetor e mantê-los sincronizados - ou seja, quando você exclui do mapa, encontra e exclui o elemento do vetor. Ou você pode criar um
map<string, pair<int,int>>
- e em seu par armazenar o tamanho () do mapa na inserção para registrar a posição, junto com o valor do int, e então quando você imprimir, usar o membro da posição para classificar.fonte
Outra maneira de implementar isso é com um em
map
vez de umvector
. Vou mostrar essa abordagem e discutir as diferenças:Basta criar uma classe que tenha dois mapas nos bastidores.
Você pode então expor um iterador para iterador
data_
na ordem adequada. A maneira como você faz isso é iterarinsertion_order_
e, para cada elemento obtido dessa iteração, faça uma pesquisa nodata_
com o valor deinsertion_order_
Você pode usar o mais eficiente
hash_map
para insertion_order, pois não se preocupa com a iteração diretainsertion_order_
.Para fazer inserções, você pode ter um método como este:
Há muitas maneiras de melhorar o design e se preocupar com o desempenho, mas este é um bom esqueleto para você começar a implementar essa funcionalidade por conta própria. Você pode torná-lo modelado e pode realmente armazenar pares como valores em data_ para que possa referenciar facilmente a entrada em insertion_order_. Mas deixo essas questões de design como um exercício :-).
Atualização : suponho que devo dizer algo sobre a eficiência do uso de mapa vs. vetor para insertion_order_
Talvez se você não for usar exclusões tanto, deve usar a abordagem vetorial. A abordagem do mapa seria melhor se você suportasse uma ordem diferente (como prioridade) em vez de uma ordem de inserção.
fonte
Aqui está uma solução que requer apenas a biblioteca de modelos padrão sem usar o multiindex do boost:
Você pode usar
std::map<std::string,int>;
evector <data>;
onde no mapa você armazena o índice da localização dos dados no vetor e o vetor armazena os dados na ordem de inserção. Aqui, o acesso aos dados tem complexidade O (log n). exibir dados no pedido de inserção tem complexidade O (n). a inserção de dados tem complexidade O (log n).Por exemplo:
fonte
Isso está um tanto relacionado à resposta de Faisals. Você pode simplesmente criar uma classe de wrapper em torno de um mapa e vetor e mantê-los sincronizados facilmente. O encapsulamento adequado permitirá que você controle o método de acesso e, portanto, qual contêiner usar ... o vetor ou o mapa. Isso evita o uso de Boost ou algo parecido.
fonte
Uma coisa que você precisa considerar é o pequeno número de elementos de dados que você está usando. É possível que seja mais rápido usar apenas o vetor. Há alguma sobrecarga no mapa que pode fazer com que seja mais caro fazer pesquisas em pequenos conjuntos de dados do que no vetor mais simples. Portanto, se você sabe que sempre usará o mesmo número de elementos, faça um benchmarking e veja se o desempenho do mapa e do vetor é o que você realmente pensa que é. Você pode descobrir que a pesquisa em um vetor com apenas 50 elementos é quase igual à do mapa.
fonte
// Deve ser como esse homem!
// Isso mantém a complexidade da inserção é O (logN) e a exclusão também é O (logN).
fonte
Use
boost::multi_index
com índices de mapa e lista.fonte
Um mapa de par (str, int) e int estático que incrementa em pares de índices de chamadas de inserção de dados. Colocar em um struct que pode retornar o int val estático com um membro index () talvez?
fonte