Czy kolejność iteracji przez std :: map jest znana (i gwarantowana przez standard)?


158

Chodzi mi o to - wiemy, że std::mapelementy są posortowane według kluczy. Powiedzmy, że klucze są liczbami całkowitymi. Jeśli wykonam iterację od std::map::begin()do std::map::end()a for, czy standard gwarantuje, że będę konsekwentnie przechodzić przez elementy z kluczami posortowane w kolejności rosnącej?


Przykład:

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;
}

Czy jest to gwarantowane do druku, 234czy jest to zdefiniowana implementacja?


Powód z życia: mam klucz std::mapz intkluczami. W bardzo rzadkich sytuacjach chciałbym powtórzyć wszystkie elementy, z kluczem, większym niż konkretna intwartość. Tak, wygląda na to, że std::vectorbyłby to lepszy wybór, ale zwróć uwagę na moje „bardzo rzadkie sytuacje”.


EDYCJA : Wiem, że elementy std::mapsą posortowane… nie trzeba na to zwracać uwagi (dla większości odpowiedzi tutaj). Napisałem to nawet w swoim pytaniu.
Pytałem o iteratory i kolejność, gdy przechodzę przez kontener. Dzięki @Kerrek SB za odpowiedź.


6
W przypadku, gdy nie wiedziałeś: w swoim prawdziwym życiu użyj, map::upper_boundaby znaleźć punkt do rozpoczęcia iteracji.
— Steve Jessop

Wiem o tym i znam dokładne miejsce, w którym zacznę iterować. Po prostu wędrowałem, jeśli zamówienie jest gwarantowane.
— Kiril Kirov

Rzadki wektor nie byłby rozsądny, gdyby twoje klucze (indeksy numeryczne) znacznie się różniły na całej planszy. Używam podobnego rozwiązania, dla którego indeks numeryczny reprezentuje kartezjańską współrzędną y w przestrzeni trójwymiarowej. Użycie wektora w tym scenariuszu zwiększyłoby zużycie pamięci o gigabajty. Więc nie sądzę, by wektor był tutaj panaceum, daleki od tego.
— Jonathan Neufeld

Nie rozumiem pytania i wyjaśnię dlaczego poprzez eksperyment myślowy. Jeśli już wiesz, że elementy są uporządkowane, jak mogłaby nie być iteracja? Co w ogóle oznacza porządkowanie, jeśli nie dotyczy iteracji? Jakie są inne przypadki, w których porządek ma znaczenie, jest wykrywalny itp.? (Odpowiedzi udzielił Konstantin .)
— podkreślenie_d

Odpowiedzi:


176

Tak, to gwarantowane. Co więcej, *begin()daje najmniejszą i *rbegin()największą elementu, określona przez operatora porównania i dwie kluczowe wartości ai bdla których wyrażenie !compare(a,b) && !compare(b,a)jest prawdziwe są uważane za równe. Domyślną funkcją porównania jest std::less<K>.

Porządkowanie nie jest szczęśliwą funkcją bonusową, ale jest raczej fundamentalnym aspektem struktury danych, ponieważ kolejność jest używana do określenia, kiedy dwa klucze są takie same (zgodnie z powyższą regułą) i do wydajnego wyszukiwania (zasadniczo binarny wyszukiwanie, które ma logarytmiczną złożoność w liczbie elementów).


std :: map jest implementowane przy użyciu drzew binarnych, więc technicznie nie jest wykonywane wyszukiwanie binarne.
— jupp0r

11
@ jupp0r: Strukturyzowanie zakresu w postaci binarnego drzewa wyszukiwania to szczególna metoda implementacji wyszukiwania binarnego w zakresie. „Wyszukiwanie binarne” jest pojęciem abstrakcyjnym, a nie konkretną implementacją. Nie ma znaczenia, czy przeskakujesz przez przesunięcia do tablicy, czy podążasz za węzłami łącza; są to tylko specyficzne sposoby „podzielenia zakresu na pół”.
— Kerrek SB

1
Wiem, że to stary post, ale aby było jasne, „wydajne wyszukiwanie” jest względne. Technicznie rzecz biorąc, std::unordered_mapma bardziej wydajny czas wyszukiwania O (1). Zaletą std::mapjest porządkowanie kluczy, ale nie wyszukiwanie.
— Adam Johnston

42

Gwarantują to wymagania dotyczące kontenerów asocjacyjnych w standardzie C ++. Np. Patrz 23.2.4 / 10 w C ++ 11:

Podstawową właściwością iteratorów kontenerów asocjacyjnych jest to, że one
iteruj przez kontenery w nie malejącej kolejności kluczy, gdzie
nie-malejąco jest definiowane przez porównanie, które zostało użyte do ich skonstruowania.
Dla dowolnych dwóch iteratorów dereferencyjnych i i j takich, że odległość od i do j wynosi
pozytywny,
  value_comp (* j, * i) == false

i 23.2.4 / 11

W przypadku kontenerów asocjacyjnych z unikalnymi kluczami obowiązuje silniejszy warunek,
  value_comp (* i, * j)! = false.

32

Myślę, że istnieje zamieszanie w strukturach danych.

W większości języków a mapjest po prostu AssociativeContainer: mapuje klucz do wartości. W „nowszych” językach jest to generalnie osiągane przy użyciu mapy mieszania, dlatego nie jest gwarantowana kolejność.

Jednak w C ++ tak nie jest:

  • std::mapto posortowany kontener asocjacyjny
  • std::unordered_map jest asocjacyjnym kontenerem opartym na tablicy skrótów wprowadzonym w C ++ 11

Tak więc, aby wyjaśnić gwarancje przy zamówieniu.

W C ++ 03:

  • std::set, std::multiset, std::mapI std::multimapsą zagwarantowane uporządkowane zgodnie z tymi przyciskami (i kryterium zestawie)
  • w std::multiseti std::multimap, norma nie narzuca żadnej gwarancji zamówienia na równoważne elementy (tj. takie, które porównują równe)

W C ++ 11:

  • std::set, std::multiset, std::mapI std::multimapsą zagwarantowane uporządkowane zgodnie z tymi przyciskami (i kryterium zestawie)
  • w std::multiseti std::multimap, norma narzuca, że równoważne elementy (te, które porównują równe sobie) są sortowane zgodnie z kolejnością wstawiania (pierwsze wstawione jako pierwsze)
  • std::unordered_*kontenery, jak sama nazwa wskazuje, nie są zamawiane. Przede wszystkim kolejność elementów może się zmienić, gdy kontener jest modyfikowany (po wstawieniu / usunięciu).

Gdy Norma mówi, że elementy są uporządkowane w sposób, oznacza to, że:

  • podczas iteracji zobaczysz elementy w zdefiniowanej kolejności
  • podczas wykonywania iteracji w odwrotnej kolejności elementy są wyświetlane w odwrotnej kolejności

Mam nadzieję, że to wyjaśni wszelkie nieporozumienia.


To nie ma nic wspólnego z moim pytaniem, przepraszam :) Wiem, które zamówiłem, a które nie. Pytam o kolejność, kiedy przechodzę przez elementy.
— Kiril Kirov

10
@KirilKirov: cóż, definicja uporządkowanego kontenera asocjacyjnego polega na tym, że podczas iteracji przez niego elementy są uporządkowane.
— Matthieu M.

Cóż, myślę, że masz rację, ale tego nie wiedziałem i właśnie o to pytałem :)
— Kiril Kirov

4

Czy to gwarantuje wydruk 234, czy zdefiniowano jego implementację?

Tak, std::mapjest to sortowany pojemnik, zamawiany przez Keydostawcę Comparator. Więc jest to gwarantowane.

Chciałbym przejść przez wszystkie elementy, z kluczem, większym niż konkretna wartość int.

To z pewnością możliwe.


3

Tak ... elementy w std::map mają ścisłą słabą kolejność, co oznacza, że ​​elementy będą składać się z zestawu (tj. Nie będzie powtórzeń kluczy, które są „równe”), a równość jest określana przez testowanie na dowolnym dwa klucze A i B, jeśli klucz A jest nie mniejszy niż klucz B i B jest nie mniejszy niż klucz A, to klucz A jest równy kluczowi B.

Mając to na uwadze, nie możesz poprawnie posortować elementów a, std::mapjeśli słaba kolejność dla tego typu jest niejednoznaczna (w twoim przypadku, gdy używasz liczb całkowitych jako typu klucza, nie stanowi to problemu). Musisz być w stanie zdefiniować operację, która definiuje całkowitą kolejność według typu, którego używasz dla kluczy w swoim std::map, w przeciwnym razie będziesz mieć tylko częściowe zamówienie dla swoich elementów lub poset, który ma właściwość, w której A może nie być porównywalne z B. W tym scenariuszu zazwyczaj zdarza się, że będziesz w stanie wstawić pary klucz / wartość, ale możesz skończyć z zduplikowanymi parami klucz / wartość, jeśli przejdziesz przez całą mapę i / lub wykryjesz „brakujące” pary klucz / wartość podczas próby wykonania std::map::find()określonej pary klucz / wartość na mapie.


Podobnie jak inne odpowiedzi, to tak naprawdę nie odpowiada na moje pytanie, w każdym razie dzięki.
— Kiril Kirov

-3

begin () może dać najmniejszy element. Ale to zależy od implementacji. Czy jest to określone w standardzie C ++? Jeśli nie, to takie założenie jest niebezpieczne.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.