J'ai actuellement un std::map<std::string,int>
qui stocke une valeur entière dans un identifiant de chaîne unique, et je recherche la chaîne. Il fait principalement ce que je veux, sauf que cela ne suit pas l'ordre d'insertion. Ainsi, lorsque j'itère la carte pour imprimer les valeurs, elles sont triées en fonction de la chaîne; mais je veux qu'ils soient triés selon l'ordre de (première) insertion.
J'ai pensé à utiliser a à la vector<pair<string,int>>
place, mais je dois rechercher la chaîne et incrémenter les valeurs entières environ 10 000 000 fois, donc je ne sais pas si a std::vector
sera beaucoup plus lent.
Y a-t-il un moyen d'utiliser std::map
ou y a-t-il un autre std
contenant qui répond mieux à mes besoins?
[Je suis sur GCC 3.4, et je n'ai probablement pas plus de 50 paires de valeurs dans mon std::map
].
Merci.
la source
Réponses:
Si vous n'avez que 50 valeurs dans std :: map, vous pouvez les copier dans std :: vector avant de les imprimer et les trier via std :: sort en utilisant le foncteur approprié.
Ou vous pouvez utiliser boost :: multi_index . Il permet d'utiliser plusieurs index. Dans votre cas, cela pourrait ressembler à ceci:
la source
Vous pouvez combiner a
std::vector
avec unestd::tr1::unordered_map
(une table de hachage). Voici un lien vers la documentation de Boost pourunordered_map
. Vous pouvez utiliser le vecteur pour suivre l'ordre d'insertion et la table de hachage pour effectuer les recherches fréquentes. Si vous effectuez des centaines de milliers de recherches, la différence entre la recherche O (log n)std::map
et O (1) pour une table de hachage peut être significative.la source
std::map
de travailler comme il se doit (c'est-à-dire en se triant au fur et à mesure que vous insérez), et a une durée d'exécution rapide. (J'ai lu ceci après avoir écrit ma version, où j'ai utilisé std :: list!)Gardez un parallèle
list<string> insertionOrder
.Lorsqu'il est temps d'imprimer, parcourez la liste et effectuez des recherches dans la carte .
la source
std::string_view
pour les clés de la carte faisant référence austd::string
dans lainsertionOrder
liste. Cela évite la copie, mais vous devez faire attention à ce que lesinsertionOrder
éléments survivent aux clés de la carte qui y font référence.Tessil a une très belle implémentation de la carte ordonnée (et de l'ensemble) qui est une licence MIT. Vous pouvez le trouver ici: plan-ordonné
Exemple de carte
la source
Si vous avez besoin des deux stratégies de recherche, vous vous retrouverez avec deux conteneurs. Vous pouvez utiliser a
vector
avec vos valeurs réellesint
, et mettre un àmap< string, vector< T >::difference_type>
côté, renvoyant l'index dans le vecteur.Pour compléter tout cela, vous pouvez encapsuler les deux dans une seule classe.
Mais je crois que boost a un conteneur avec plusieurs indices.
la source
Ce que vous voulez (sans recourir à Boost), c'est ce que j'appelle un "hash ordonné", qui est essentiellement un mashup d'un hachage et d'une liste chaînée avec des clés de chaîne ou de nombre entier (ou les deux en même temps). Un hachage ordonné maintient l'ordre des éléments lors de l'itération avec la performance absolue d'un hachage.
J'ai mis en place une bibliothèque d'extraits de code C ++ relativement nouvelle qui remplit ce que je considère comme des trous dans le langage C ++ pour les développeurs de bibliothèques C ++. Va ici:
https://github.com/cubiclesoft/cross-platform-cpp
Saisir:
Si les données contrôlées par l'utilisateur sont placées dans le hachage, vous pouvez également souhaiter:
Invoquez-le:
Je suis tombé sur ce fil SO lors de ma phase de recherche pour voir si quelque chose comme OrderedHash existait déjà sans me demander de déposer dans une bibliothèque massive. J'étais déçu. Alors j'ai écrit le mien. Et maintenant je l'ai partagé.
la source
Vous ne pouvez pas faire cela avec une carte, mais vous pouvez utiliser deux structures distinctes - la carte et le vecteur et les garder synchronisés - c'est-à-dire lorsque vous supprimez de la carte, recherchez et supprimez l'élément du vecteur. Ou vous pouvez créer un
map<string, pair<int,int>>
- et dans votre paire stocker la taille () de la carte lors de l'insertion pour enregistrer la position, ainsi que la valeur de l'int, puis lorsque vous imprimez, utilisez le membre de position pour trier.la source
Une autre façon de l'implémenter est d'
map
utiliser un au lieu d'unvector
. Je vais vous montrer cette approche et discuter des différences:Créez simplement une classe avec deux cartes dans les coulisses.
Vous pouvez ensuite exposer un itérateur à un itérateur
data_
dans le bon ordre. La façon dont vous faites cela est de parcouririnsertion_order_
, et pour chaque élément que vous obtenez de cette itération, faites une recherche dans ledata_
avec la valeur deinsertion_order_
Vous pouvez utiliser le plus efficace
hash_map
pour insertion_order car vous ne vous souciez pas de l'itération directeinsertion_order_
.Pour faire des insertions, vous pouvez avoir une méthode comme celle-ci:
Il existe de nombreuses façons d'améliorer la conception et de vous soucier des performances, mais c'est un bon squelette pour vous aider à implémenter cette fonctionnalité vous-même. Vous pouvez créer un modèle et stocker des paires en tant que valeurs dans data_ afin de pouvoir facilement référencer l'entrée dans insertion_order_. Mais je laisse ces problèmes de conception comme un exercice :-).
Mise à jour : je suppose que je devrais dire quelque chose sur l'efficacité de l'utilisation de la carte par rapport au vecteur pour insertion_order_
Peut-être que si vous n'utilisez pas autant de suppressions, vous devriez utiliser l'approche vectorielle. L'approche de la carte serait meilleure si vous preniez en charge un ordre différent (comme la priorité) au lieu d'un ordre d'insertion.
la source
Voici une solution qui ne nécessite que la bibliothèque de modèles standard sans utiliser le multiindex de boost:
Vous pouvez utiliser
std::map<std::string,int>;
etvector <data>;
où dans la carte vous stockez l'index de l'emplacement des données dans le vecteur et stocke les données vectorielles dans l'ordre d'insertion. Ici, l'accès aux données a une complexité O (log n). l'affichage des données dans l'ordre d'insertion a une complexité O (n). l'insertion de données a une complexité O (log n).Par exemple:
la source
Ceci est quelque peu lié à la réponse de Faisals. Vous pouvez simplement créer une classe wrapper autour d'une carte et d'un vecteur et les garder facilement synchronisés. Une encapsulation correcte vous permettra de contrôler la méthode d'accès et donc le conteneur à utiliser ... le vecteur ou la carte. Cela évite d'utiliser Boost ou quelque chose comme ça.
la source
Une chose dont vous devez tenir compte est le petit nombre d'éléments de données que vous utilisez. Il est possible qu'il soit plus rapide d'utiliser uniquement le vecteur. Il y a une surcharge dans la carte qui peut rendre plus coûteuse les recherches dans de petits ensembles de données que le vecteur plus simple. Donc, si vous savez que vous utiliserez toujours à peu près le même nombre d'éléments, faites une analyse comparative et voyez si les performances de la carte et du vecteur sont ce que vous pensez vraiment. Vous pouvez trouver que la recherche dans un vecteur avec seulement 50 éléments est presque identique à la carte.
la source
// Devrait être comme cet homme!
// Ceci maintient la complexité de l'insertion est O (logN) et la suppression est également O (logN).
la source
À utiliser
boost::multi_index
avec les index de carte et de liste.la source
Une carte de paires (str, int) et int statique qui s'incrémente lors des appels d'insertion indexe les paires de données. Mettre dans une structure qui peut retourner le statique int val avec un membre index () peut-être?
la source