10
votes

Tri de STD :: Carte par valeur avant la sortie et détruire

Je suis conscient que la carte n'est pas prête à être triée. Il est fortement optimisé pour un accès à clé rapide et aléatoire et ne prend en charge pas std :: Trier .

Mon problème actuel est que j'ai une carte complète que je ne vais plus utiliser. J'ai juste besoin d'extraire 10 paires dans la valeur (int) commander et de le détruire.

La meilleure chose à faire, si c'était possible, il serait possible de trier en place, puis de l'itéraire 10 fois, mais cela n'est apparemment pas une solution.

J'essaie différentes solutions comme passez via un multimap (pour autoriser les touches en double), mais j'aimerais savoir s'il y a une solution plus élégante, à l'aide de STL algorithmes autant que possible.

EDIT:

J'utilise une carte car pour la 99% du temps, j'en ai besoin de carte: des recherches clés rapides pour augmenter les valeurs. Il suffit de nécessiter un bon moyen d'extraire plus tard d'ordre de valeur lorsque je n'ai plus besoin de la carte.

L'approche actuelle devrait être:

  • std :: copier la carte (std :: string, int) à un vecteur (paire (STD :: String, int))
  • Trier le vecteur
  • Obtenez les 10 premières valeurs
  • détruire le vecteur et la carte

2 commentaires

Vos exigences ne sont très pas claires pour moi. IIUC, vous devez trouver 10 entrées dans la carte par leur valeur au lieu de leur clé? Et une fois que vous les avez, qu'allez-vous faire avec eux? Je demande parce que "détruire" est un terme vague et je ne peux pas deviner la signification d'un std :: paire . Sont-ils à retirer de la carte? (Probablement pas, car vous avez dit que vous n'avez plus besoin de la carte. Mais quoi d'autre?)


La carte va être détruite pour que je me fiche de ce qui se passe plus tard, il faut juste avoir ces 10 valeurs


5 Réponses :


1
votes

Si vous iTérez l'utilisation de la carte Itératrice, vous obtiendrez les éléments triés sur la clé car il utilise l'arborescence binaire équilibrée pour stocker les valeurs. Donc, vous pourriez simplement extraire les 10 valeurs de celui-ci en utilisant les itérateurs. Est-ce ce que vous voulez ou que vous voulez faire autre chose? S'il vous plaît clarifier.

Edit: Au lieu d'utiliser le vecteur et le tri, vous pouvez utiliser directement défini et transmettre la fonction de comparaison. Ensuite, vous pouvez extraire les 10 meilleurs éléments. Ceci est mon code de test: xxx


3 commentaires

"J'ai juste besoin d'extraire 10 paires de valeur (int) l'ordre et de le détruire."


Quel est le type de votre carte, quelle est la clé et quelle est la valeur?


Désolé pour cela, le type de carte s'est échappé dans l'organe de la question, j'ai résolu cela.



7
votes

Pour itération par valeur, vous pouvez utiliser boost :: Multi_index . Il ressemblera comme suit: xxx

Vous pouvez utiliser n'importe quel index pour itération ( val_str ou val_int ).


0 commentaires

26
votes

Les cartes sont stockées comme un arbre trié dans l'ordre clé. Vous voulez les 10 plus petites (ou les plus grandes) valeurs entières et leurs clés, non?

Dans ce cas, itérer la carte et mettre toutes les paires de la valeur de clé dans un vecteur de paires ( std :: vecteur >) code>. Je pense que vous pouvez simplement utiliser le constructeur deux-itérator-arg constructeur de std :: vecteur pour cela. Ensuite, utilisez std :: partiel_sort code> sur le vecteur. Spécifiez un comparateur à partial_sort, qui compare des paires en comparant simplement la valeur INT, ignorant la chaîne de clé. Ensuite, vous avez les 10 paires que vous voulez au début du vecteur et le reste du vecteur contient les paires restantes dans un ordre non spécifié. P>

code (non testé): p>

typedef std::pair<std::string, int> mypair;

struct IntCmp {
    bool operator()(const mypair &lhs, const mypair &rhs) {
        return lhs.second < rhs.second;
    }
};


void print10(const std::map<std::string,int> &mymap) {
    std::vector<mypair> myvec(mymap.begin(), mymap.end());
    assert(myvec.size() >= 10);
    std::partial_sort(myvec.begin(), myvec.begin() + 10, myvec.end(), IntCmp());

    for (int i = 0; i < 10; ++i) {
        std::cout << i << ": " << myvec[i].first 
            << "-> " << myvec[i].second << "\n";
    }
}


0 commentaires

1
votes

Peut ne pas être le moyen le plus élégant, mais vous pouvez les trier via une valeur dans un ensemble comme: xxx


0 commentaires

1
votes

Une autre possibilité est de construire une carte inversée. Pour vous, ce serait std :: map code>. Les entrées dans la carte inverse sont triées par leur valeur.

Voici ce que j'ai dans ma boîte à outils pour de telles occasions: P>

template< typename TK, typename TV, class TP, class TA, typename T1, typename T2 >
inline void asserted_insert(std::map<TK,TV,TP,TA>& m, const T1& k, const T2& v)
{
  typedef std::map<TK,TV,TP,TA>                   map_type;
  typedef typename map_type::value_type           value_type;
  assert( m.insert(value_type(k,v)).second );
}

template< class TMap > struct reverse_map;
template< typename T1, typename T2 > struct reverse_map< std::map<T1,T2> > {
  typedef std::map<T2,T1>                         result_t;
};

template< typename T1, typename T2, class TP1, class TA1, class TP2, class TA2 >
inline void build_reverse_map(const std::map<T1,T2,TP1,TA1>& map, std::map<T2,T1,TP2,TA2>& reverse_map)
{
  typedef std::map<T1,T2,TP1,TA1>                 map_type;

  for( typename map_type::const_iterator it=map.begin(),
                                        end=map.end(); it!=end; ++it ) {
    asserted_insert( reverse_map, it->second, it->first );
  }
}


0 commentaires