Je dois trier une carte par valeur, puis par clé. J'ai une carte avec un contenu comme celui-ci ...
1 realistically
8 really
4 reason
3 reasonable
1 reasonably
1 reassemble
1 reassembled
2 recognize
92 record
48 records
7 recs
Il me faut mettre les valeurs dans l’ordre, mais le facteur clé est que les clés doivent être dans l’ordre alphabétique après que les valeurs sont dans l’ordre. Quelle est la meilleure manière de s'occuper de ça?
std::map
va trier ses éléments par keys
. Peu importe la values
lors du tri.
Vous pouvez utiliser std::vector<std::pair<K,V>>
puis le trier en utilisant std::sort
suivi de std::stable_sort
:
std::vector<std::pair<K,V>> items;
//fill items
//sort by value using std::sort
std::sort(items.begin(), items.end(), value_comparer);
//sort by key using std::stable_sort
std::stable_sort(items.begin(), items.end(), key_comparer);
Le premier tri doit utiliser std::sort
puisqu'il s'agit de nlog(n)
, puis utiliser std::stable_sort
qui est n(log(n))^2
dans le pire des cas.
Notez que bien que std::sort
soit choisi pour des raisons de performances, il est nécessaire que std::stable_sort
soit utilisé pour un ordre correct, car vous souhaitez que la valeur par ordre soit préservée.
@gsf a noté dans le commentaire, vous pouvez utiliser only std::sort
si vous choisissez un comparateur qui compare values
en premier, et s’ils sont égaux, triez la keys
.
auto cmp = [](std::pair<K,V> const & a, std::pair<K,V> const & b)
{
return a.second != b.second? a.second < b.second : a.first < b.first;
};
std::sort(items.begin(), items.end(), cmp);
Cela devrait être efficace.
Mais attendez, il existe une meilleure approche: store std::pair<V,K>
au lieu de std::pair<K,V>
et vous n’avez donc pas besoin de comparateur - le comparateur standard pour std::pair
serait suffisant, car il compare first
(qui est V
) en premier puis second
qui est K
:
std::vector<std::pair<V,K>> items;
//...
std::sort(items.begin(), items.end());
Cela devrait bien fonctionner.
Vous pouvez utiliser std::set
au lieu de std::map
.
Vous pouvez stocker la clé et la valeur dans std::pair
et le type de conteneur ressemblera à ceci:
std::set< std::pair<int, std::string> > items;
std::set
triera ses valeurs en fonction des clés d'origine et des valeurs stockées dans std::map
.
std::map
trie déjà les valeurs à l'aide d'un prédicat que vous définissez ou std::less
si vous n'en fournissez pas. std::set
stockera également les éléments dans l'ordre du comparateur défini. Cependant, ni set ni map ne vous permettent d'avoir plusieurs clés. Je suggérerais de définir un std::map<int,std::set<string>
si vous voulez accomplir cela en utilisant uniquement votre structure de données. Vous devez également vous rendre compte que std::less
pour string va trier lexicographiquement et non par ordre alphabétique.
EDIT: Les deux autres réponses font un bon point. Je suppose que vous voulez les commander dans une autre structure ou pour les imprimer.
"Meilleur" peut signifier différentes choses. Voulez-vous dire "plus facile", "le plus rapide", "le plus efficace", "le moins de code", "le plus lisible?"
L'approche la plus évidente consiste à effectuer une boucle double. Au premier passage, ordonnez les valeurs:
if(current_value > examined_value)
{
current_value = examined_value
(and then swap them, however you like)
}
Ensuite, lors de la deuxième passe, alphabétisez les mots, mais seulement si leurs valeurs correspondent.
if(current_value == examined_value)
{
(alphabetize the two)
}
À proprement parler, il s’agit d’une "sorte de bulle" lente, car chaque fois que vous effectuez un échange, vous devez tout recommencer. Une "passe" est terminée lorsque vous parcourez toute la liste sans effectuer aucun échange.
Il existe d'autres algorithmes de tri, mais le principe serait le même: ordre par valeur, puis par ordre alphabétique.