2010-04-23 19 views
43

Come posso implementare l'ordinamento della mappa STL in base al valore?Come posso ordinare una mappa STL in base al valore?

Ad esempio, ho una mappa m:

map<int, int> m; 
m[1] = 10; 
m[2] = 5; 
m[4] = 6; 
m[6] = 1; 

mi piacerebbe ordinare quella mappa per valore m s'. Quindi, se stampare la mappa, mi piacerebbe ottenere il risultato come segue:

m[6] = 1 
m[2] = 5 
m[4] = 6 
m[1] = 10 

Come posso ordinare la mappa in questo modo? C'è un modo in cui posso gestire la chiave e il valore con valori ordinati?

+0

Vedere 'boost :: bimap' –

risposta

25

È possibile creare una seconda mappa, con i valori della prima mappa come chiavi e le chiavi della prima mappa come valori.

Questo funziona solo se tutti i valori sono distinti. Se non puoi assumere questo, allora hai bisogno di costruire un multimap invece di una mappa.

+1

haha, potrebbe essere la soluzione perfetta. –

+52

Solo se i valori sono tutti distinti. :-P –

+14

se no, usa un multimap. – swegi

14

Mi chiedo come è possibile implementare l'ordinamento della mappa STL in base al valore.

Non è possibile, per definizione. Una mappa è una struttura dati che ordina il suo elemento per chiave.

+1

Come posso implementare questa funzione? Ho bisogno di questa funzione. –

+1

@Charlie Epps: con un'altra mappa? Ogni volta che aggiungi una chiave/valore alla prima mappa, aggiungi un valore/tasto al secondo ... – paercebal

4

È necessario utilizzare Boost.Bimap per questo genere di cose.

+0

... a condizione che la mappatura sia uno a uno. – Vlad

+0

In realtà, Boost.Bimap supporta operazioni non uno a uno. Ad esempio, 'bimap , set_of >' – rlbond

57

Escludere prima tutte le coppie chiave-valore in set<pair<K, V> >, dove il set è costruito con un functor minore che confronta solo il secondo valore della coppia. In questo modo, il tuo codice funziona ancora anche se i tuoi valori non sono tutti distinti.

Oppure scaricare le coppie chiave-valore in un vector<pair<K, V> >, quindi ordinare quel vettore con lo stesso minore in seguito.

+0

Una domanda, non useresti la doppia memoria adesso? – atoMerz

+0

@AtoMerZ Se si tratta di un problema, è possibile impostare i riferimenti per il mantenimento del set. Se sono già riferimenti o tipi piccoli, non importa. –

+3

Per ordinare il vettore di coppie: http://stackoverflow.com/questions/279854/how-do-i-sort-a-vector-of-pairs-based-on-the-second-element-of-the- coppia – juanmirocks

0

Creare un'altra mappa, fornire una funzione meno() in base al valore non chiave, e la funzione deve restituire true se la valore1 < = value2 (non strettamente <). In questo caso, anche gli elementi con valori non distinti possono essere ordinati.

1

Ho appena fatto una domanda simile nel mio libro C++. La risposta mi è venuta potrebbe non essere molto efficiente, anche se:

int main() 
{ 
    string s; 
    map<string, int> counters; 

    while(cin >> s) 
     ++counters[s]; 

    //Get the largest and smallest values from map 
    int beginPos = smallest_map_value(counters); 
    int endPos = largest_map_value(counters); 

    //Increment through smallest value to largest values found 
    for(int i = beginPos; i <= endPos; ++i) 
    { 
     //For each increment, go through the map... 
     for(map<string, int>::const_iterator it = counters.begin(); it != counters.end(); ++it) 
     { 
      //...and print out any pairs with matching values 
      if(it->second == i) 
      { 
       cout << it->first << "\t" << it->second << endl; 
      } 
     } 
    } 
    return 0; 
} 

//Find the smallest value for a map<string, int> 
int smallest_map_value(const map<string, int>& m) 
{ 
    map<string, int>::const_iterator it = m.begin(); 
    int lowest = it->second; 
    for(map<string, int>::const_iterator it = m.begin(); it != m.end(); ++it) 
    { 
     if(it->second < lowest) 
      lowest = it->second; 
    } 
    return lowest; 
} 

//Find the largest value for a map<string, int> 
int largest_map_value(const map<string, int>& m) 
{ 
    map<string, int>::const_iterator it = m.begin(); 
    int highest = it->second; 
    for(map<string, int>::const_iterator it = m.begin(); it != m.end(); ++it) 
    { 
     if(it->second > highest) 
      highest = it->second; 
    } 
    return highest; 
} 
0

Sulla base di un'idea di @ swegi, ho implementato una soluzione in c++11 utilizzando un multimap:

map<int, int> m = {{1, 10}, {2, 5}, {4, 6}, {6, 1}}; 
multimap<int, int> mm; 

for(auto const &kv : m) 
    mm.insert(make_pair(kv.second, kv.first)); // Flip the pairs. 

for(auto const &kv : mm) 
    cout << "m[" << kv.second << "] = " << kv.first << endl; // Flip the pairs again. 

Code on Ideone

anche io implementato una soluzione C++ 11 basata sull'idea di @Chris utilizzando un vettore di coppie. Per il corretto smistamento, ho fornire un lambda expression come confronto functor:

map<int, int> m = {{1, 10}, {2, 5}, {4, 6}, {6, 1}}; 
using mypair = pair<int, int>; 

vector<mypair> v(begin(m), end(m)); 

sort(begin(v), end(v), [](const mypair& a, const mypair& b) { return a.second < b.second; }); 

for(auto const &p : v) 
    cout << "m[" << p.first << "] = " << p.second << endl; 

Code on Ideone

La prima soluzione è più compatta, ma entrambe le soluzioni devono avere all'incirca le stesse prestazioni.L'inserimento in un multimap è di O (log n), ma questo deve essere fatto per n voci, con conseguente O (n log n). L'ordinamento del vettore nella seconda soluzione comporta inoltre O (n log n).

Ho anche provato l'idea di @Chris sull'utilizzo di un set di coppie. Tuttavia, non funzionerà se i valori non sono tutti distinti. L'uso di un functor che confronta solo il secondo elemento della coppia non aiuta. Se prima inserisci make_pair(1, 1) nel set e poi provi a inserire make_pair(2, 1), la seconda coppia non verrà inserita, poiché entrambe le coppie sono identiche a quella serie. Puoi vedere quell'effetto here on Ideone.

Problemi correlati