L'ordine di iterazione tramite std :: map è noto (e garantito dallo standard)?


158

Quello che voglio dire è che sappiamo che gli std::mapelementi sono ordinati in base alle chiavi. Quindi, supponiamo che le chiavi siano numeri interi. Se mi iterare da std::map::begin()a std::map::end()utilizzare un for, fa la garanzia standard che io iterare di conseguenza attraverso gli elementi con chiavi, in ordine crescente?


Esempio:

std::map<int, int> map_;
map_[1] = 2;
map_[2] = 3;
map_[3] = 4;
for( std::map<int, int>::iterator iter = map_.begin();
     iter != map_.end();
     ++iter )
{
    std::cout << iter->second;
}

La stampa 234è garantita o l'implementazione è definita?


Motivo della vita reale: ho un std::mapcon le intchiavi. In situazioni molto rare, vorrei scorrere tutti gli elementi, con la chiave, più di un intvalore concreto . Sì, sembra che std::vectorsarebbe la scelta migliore, ma nota le mie "situazioni molto rare".


EDIT : So che gli elementi di std::mapsono ordinati .. non c'è bisogno di segnalarlo (per la maggior parte delle risposte qui). L'ho anche scritto nella mia domanda.
Stavo chiedendo degli iteratori e dell'ordine quando sto iterando attraverso un contenitore. Grazie @Kerrek SB per la risposta.


6
Nel caso in cui non lo sapessi: nella tua vita reale puoi usare map::upper_boundil punto per iniziare a iterare.
Steve Jessop,

Lo so e conosco il posto esatto in cui inizierei a ripetere. Ho appena vagato se l'ordine è garantito.
Kiril Kirov,

Un vettore sparso non sarebbe sensato se le tue chiavi (indici numerici) variano enormemente su tutta la linea. Sto usando una soluzione simile per la quale l'indice numerico rappresenta una coordinata y cartesiana nello spazio tridimensionale. L'uso di un vettore in questo scenario aumenterebbe la mia impronta di memoria di gigabyte. Quindi non penso che il vettore sia una panacea qui, tutt'altro.
Jonathan Neufeld,

Non capisco la domanda e spiegherò perché attraverso un esperimento mentale. Se sai già che gli elementi sono ordinati, come potrebbe non essere l'iterazione? Cosa significa anche ordinare, se non si applica all'iterazione? Quali altri casi ci sono in cui l'ordine conta, è rilevabile, ecc.? (La risposta fu data da Konstantin .)
underscore_d

Risposte:


176

Sì, è garantito. Inoltre, *begin()ti dà l' *rbegin()elemento più piccolo e più grande, come determinato dall'operatore di confronto, e due valori chiave ae bper i quali l'espressione !compare(a,b) && !compare(b,a)è vera sono considerati uguali. La funzione di confronto predefinita è std::less<K>.

L'ordinamento non è una caratteristica bonus fortunato, ma piuttosto è un aspetto fondamentale della struttura dei dati, poiché l'ordinamento viene utilizzato per determinare quando due chiavi sono uguali (secondo la regola sopra) e per eseguire una ricerca efficiente (essenzialmente un binario ricerca, che ha complessità logaritmica nel numero di elementi).


std :: map viene implementato usando alberi binari, quindi tecnicamente non viene eseguita alcuna ricerca binaria.
jupp0r,

11
@ jupp0r: strutturare un intervallo come un albero di ricerca binario è un metodo particolare per implementare la ricerca binaria attraverso l'intervallo. La "ricerca binaria" è un concetto astratto piuttosto che un'implementazione particolare. Non importa se si passa attraverso gli offset in un array o si seguono nodi di collegamento; quelli sono solo modi specifici di "sezionare la gamma".
Kerrek SB,

1
So che questo è un vecchio post, ma per essere chiari la "ricerca efficiente" è relativa. Tecnicamente std::unordered_mapha un tempo di ricerca più efficiente di O (1). Il vantaggio std::mapè nell'ordinamento delle chiavi, ma non nella ricerca.
Adam Johnston,

42

Ciò è garantito dai requisiti del contenitore associativo nello standard C ++. Ad esempio, vedere 23.2.4 / 10 in C ++ 11:

La proprietà fondamentale degli iteratori di contenitori associativi è che essi
scorrere i contenitori nell'ordine non discendente delle chiavi dove
non discendente è definito dal confronto che è stato usato per costruirli.
Per due iteratori dichiarabili i e j tale che la distanza da i a j sia
positivo,
  value_comp (* j, * i) == false

e 23.2.4 / 11

Per i contenitori associativi con chiavi univoche vale la condizione più forte,
  value_comp (* i, * j)! = false.

32

Penso che ci sia confusione nelle strutture di dati.

Nella maggior parte delle lingue, a mapè semplicemente un AssociativeContainer: associa una chiave a un valore. Nelle lingue "più recenti", ciò viene generalmente ottenuto utilizzando una mappa hash, quindi non viene garantito alcun ordine.

In C ++, tuttavia, non è così:

  • std::mapè un contenitore associativo ordinato
  • std::unordered_map è un contenitore associativo basato su tabella hash introdotto in C ++ 11

Quindi, al fine di chiarire le garanzie sugli ordini.

In C ++ 03:

  • std::set, std::multiset, std::mapE std::multimapsono garantiti da ordinare in base ai tasti (e il criterio fornito)
  • in std::multisete std::multimap, lo standard non impone alcuna garanzia di ordine su elementi equivalenti (cioè quelli che si equivalgono)

In C ++ 11:

  • std::set, std::multiset, std::mapE std::multimapsono garantiti da ordinare in base ai tasti (e il criterio fornito)
  • in std::multisete std::multimap, lo Standard impone che gli elementi equivalenti (quelli che si equivalgono) siano ordinati secondo il loro ordine di inserimento (prima inseriti per primi)
  • std::unordered_*i contenitori sono, come suggerisce il nome, non ordinati. In particolare, l'ordine degli elementi può cambiare quando il contenitore viene modificato (all'inserimento / eliminazione).

Quando lo standard dice che gli elementi sono ordinati in un certo senso, significa che:

  • durante l'iterazione, vedi gli elementi nell'ordine definito
  • quando si scorre in senso inverso, si vedono gli elementi nell'ordine opposto

Spero che questo chiarisca ogni confusione.


Questo non ha nulla a che fare con la mia domanda, scusa :) So quale è stato ordinato e quale no. E sto chiedendo l'ordine quando sto ripetendo gli elementi.
Kiril Kirov,

10
@KirilKirov: beh, la definizione di un contenitore associativo ordinato è che quando si scorre attraverso di esso gli elementi sono ordinati.
Matthieu M.

Beh, immagino tu abbia ragione, ma non lo sapevo ed è esattamente quello che stavo chiedendo :)
Kiril Kirov

4

Questo è garantito per la stampa 234 o la sua implementazione è definita?

Sì, std::mapè un contenitore ordinato, ordinato da Keycon il fornito Comparator. Quindi è garantito.

Vorrei scorrere tutti gli elementi, con la chiave, più di un valore int concreto.

Questo è sicuramente possibile.


3

Sì ... gli elementi in a std::map hanno un rigoroso ordinamento debole, nel senso che gli elementi saranno composti da un set (cioè, non ci saranno ripetizioni di chiavi che sono "uguali"), e l'uguaglianza è determinata testando su qualsiasi due chiavi A e B, che se la chiave A non è inferiore alla chiave B e B non è inferiore a A, allora la chiave A è uguale alla chiave B.

Detto questo, non puoi ordinare correttamente gli elementi di a std::mapse l'ordinamento debole per quel tipo è ambiguo (nel tuo caso, dove stai usando numeri interi come tipo di chiave, non è un problema). Devi essere in grado di definire un'operazione che definisce un ordine totale sul tipo che stai usando per le chiavi nel tuo std::map, altrimenti avrai solo un ordine parziale per i tuoi elementi, o poset, che ha proprietà dove A potrebbe non essere paragonabile a B. Ciò che accadrà in genere in questo scenario è che sarai in grado di inserire le coppie chiave / valore, ma potresti finire con coppie duplicate chiave / valore se esegui l'iterazione dell'intera mappa e / o rilevi "mancante" coppie chiave / valore quando si tenta di eseguire una std::map::find()coppia chiave / valore specifica nella mappa.


Come le altre risposte, questo in realtà non risponde alla mia domanda, grazie comunque.
Kiril Kirov,

-3

begin () può fornire l'elemento più piccolo. Ma dipende l'implementazione. È specificato nello standard C ++? Altrimenti, è pericoloso fare questo presupposto.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.