Std :: map üzerinden yineleme sırası biliniyor mu (standart tarafından garanti ediliyor)?


158

Demek istediğim - std::mapöğelerinin anahtarlara göre sıralandığını biliyoruz . Diyelim ki anahtarlar tamsayı. I yinelerler Eğer std::map::begin()için std::map::end()bir kullanma for, ben tuşlarıyla elemanları aracılığıyla dolayısıyla yineleme edeceğiz standart garanti yapar, artan düzende sıralanır?


Misal:

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

Bunun yazdırılması garanti ediliyor 234mu yoksa uygulama tanımlanmış mı?


Gerçek hayat nedeni: Anahtarları olan bir a std::mapvar int. Çok nadir durumlarda, somut bir intdeğerden daha büyük, tüm unsurları tekrarlamak isterim . Evet, std::vectordaha iyi bir seçim gibi görünüyor , ama "çok nadir durumlar" a dikkat edin.


DÜZENLEME : Biliyorum, öğeleri std::mapsıralanmıştır .. işaret etmek gerek (burada cevapların çoğu için). Hatta soruma yazdım bile.
Bir konteynerden yinelediğimde yineleyiciler ve düzen hakkında soruyordum. Cevap için @Kerrek SB'e teşekkürler.


6
Bilmiyor olmanız durumunda: gerçek hayatınızda map::upper_bound, yinelemeye başlama noktasını bulmak için kullanabilirsiniz .
Steve Jessop

Bunu biliyorum ve yinelemeye başlayacağım tam yeri biliyorum. Sipariş garanti edilirse dolaştım.
Kiril Kirov

Anahtarlarınız (sayısal indeksler) kartta muazzam bir şekilde değişiyorsa, seyrek bir vektör mantıklı olmaz. Sayısal dizin 3 boyutlu alanda bir Kartezyen y koordinatını temsil eden benzer bir çözüm kullanıyorum. Bu senaryoda bir vektör kullanılması, bellek ayak izimi gigabayt artırır. Bu yüzden vektörün burada her derde deva olduğunu düşünmüyorum.
Jonathan Neufeld

Soruyu anlamıyorum ve neden bir düşünce deneyi yoluyla açıklayacağım. Elemanların sipariş edildiğini zaten biliyorsanız, tekrarlama nasıl olamazdı? Yineleme için geçerli değilse sipariş vermek ne demektir? Siparişin önemli olduğu, tespit edilebildiği vb. Başka hangi durumlar vardır? (Cevap Konstantin tarafından verildi .)
underscore_d

Yanıtlar:


176

Evet, bu garantili. Ayrıca, karşılaştırma işleci tarafından belirlenen *begin()en küçük ve *rbegin()en büyük öğeyi verir ave bifadenin !compare(a,b) && !compare(b,a)doğru olduğu iki anahtar değer eşit kabul edilir. Varsayılan karşılaştırma işlevi std::less<K>.

Sıralama şanslı bir bonus özellik değildir, ancak sipariş iki anahtarın ne zaman aynı olduğunu (yukarıdaki kural ile) belirlemek ve etkili bir arama (aslında bir ikili) gerçekleştirmek için kullanıldığı için veri yapısının temel bir yönüdür. eleman sayısında logaritmik karmaşıklığa sahip arama).


std :: map ikili ağaçlar kullanılarak uygulanır, dolayısıyla teknik olarak ikili arama yapılmaz.
jupp0r

11
@ jupp0r: Bir aralığı ikili arama ağacı olarak yapılandırmak, aralık boyunca ikili aramayı uygulamak için özel bir yöntemdir. "İkili arama" belirli bir uygulamadan ziyade soyut bir kavramdır. Ofsetlerden bir diziye atlamak veya bağlantı düğümlerini takip etmek önemli değildir; bunlar sadece "menzili ikiye bölmenin" spesifik yoludur.
Kerrek SB

1
Bu eski bir yazı olduğunu biliyorum, ama net olmak gerekirse "verimli arama" göreceli. Teknik std::unordered_mapolarak O (1) 'in daha verimli bir arama süresine sahiptir. Avantajı std::mapanahtar sıralamasıdır, ancak arama değildir.
Adam Johnston

42

Bu, C ++ standardındaki İlişkisel kapsayıcı gereksinimleri tarafından garanti edilir. Örneğin C ++ 11'de 23.2.4 / 10'a bakınız:

İlişkilendirilebilir kapların yineleyicilerinin temel özelliği,
kaplar boyunca azalan anahtar sırasına göre yineleyin.
iniş yapmama, onları inşa etmek için kullanılan karşılaştırma ile tanımlanır.
Herhangi bir iki silinebilir olmayan yineleyici için, i ve j arasındaki mesafe
pozitif,
  value_comp (* j, * i) == yanlış

ve 23.2.4 / 11

Benzersiz anahtarlara sahip ilişkilendirilebilir kaplar için daha güçlü koşul,
  value_comp (* i, * j)! = yanlış.

32

Veri yapılarında bir karışıklık olduğunu düşünüyorum.

Çoğu dilde, a mapsadece bir AssociativeContainer'dır: bir anahtarı bir değere eşler. "Daha yeni" dillerde, bu genellikle bir karma harita kullanılarak gerçekleştirilir, bu nedenle herhangi bir düzen garanti edilmez.

Ancak C ++ 'da bu böyle değildir:

  • std::mapa, kriteri birleştirici konteyner
  • std::unordered_map C ++ 11'de tanıtılan karma tablo tabanlı bir ilişkisel kapsayıcıdır

Yani, sipariş üzerine garantileri netleştirmek için.

C ++ 03'te:

  • std::set, std::multiset, std::mapVe std::multimaptuşlara göre sipariş edilmesi garanti (ve ölçüt birlikte) vardır
  • içinde std::multisetve std::multimap, standart eşdeğer elemanlar ile ilgili herhangi bir sırada garanti empoze etmez (örneğin, eşit karşılaştırma olanlar)

C ++ 11'de:

  • std::set, std::multiset, std::mapVe std::multimaptuşlara göre sipariş edilmesi garanti (ve ölçüt birlikte) vardır
  • içinde std::multisetve std::multimap, standart getirir bu eşdeğer elemanları (göre eş olanlar) kendi yerleştirme düzenine göre sıralanır (ilk önce eklenmiştir)
  • std::unordered_*kaplar, adından da anlaşılacağı gibi sipariş edilmemiştir. En önemlisi, öğelerin sırası olabilir kap (ekleme / silinmesi üzerine) modifiye zaman değişir.

Standart, öğelerin bir şekilde sipariş edildiğini söylediğinde, şu anlama gelir:

  • yinelendiğinde, öğeleri tanımlanan sırayla görürsünüz
  • tersine yinelendiğinde, öğeleri ters sırada görürsünüz

Umarım bu karışıklığı giderir.


Bunun sorumla ilgisi yok, üzgünüm :) Hangisinin sipariş edildiğini ve hangisinin sipariş edildiğini biliyorum. Ve elementleri tekrarlarken siparişi istiyorum.
Kiril Kirov

10
@KirilKirov: iyi, sıralı bir ilişkisel kabın tanımı , içinden yinelendiğinde elemanların sipariş edilmesidir.
Matthieu M.

Sanırım haklısın, ama bunu bilmiyordum ve tam olarak sorduğum şey bu :)
Kiril Kirov

4

Bunun 234 yazdırılması garanti ediliyor mu yoksa uygulaması tanımlanmış mı?

Evet, verilen ile birlikte std::mapsıralanmış bir kaptır . Böylece garanti edilir.KeyComparator

Somut bir int değerinden daha büyük, tüm unsurları tekrarlamak istiyorum.

Bu kesinlikle mümkün.


3

Evet ... std::mapbir öğedeki öğelerin katı bir zayıf sıralaması vardır, yani öğelerin bir kümeden oluşacağı (yani, "eşit" olan anahtarların tekrarı olmayacaktır) ve eşitlik, herhangi bir A ve B tuşları, A tuşu B tuşundan az değilse ve B A'dan az değilse, A tuşu B tuşuna eşittir.

Bununla birlikte, bu tür için std::mapzayıf sıralama belirsizse , öğelerini düzgün bir şekilde sıralayamazsınız (sizin durumunuzda, tamsayıları anahtar türü olarak kullandığınız yerde, bu bir sorun değildir). Bilgisayarınızdaki anahtarlar için kullandığınız türde toplam bir sipariş tanımlayan bir işlem tanımlayabilmeniz gerekir std::map, aksi takdirde öğeleriniz için yalnızca kısmi bir siparişiniz veya A'nın karşılaştırılamayacağı bir özelliğe sahip olan posetiniz olur. B. Bu senaryoda tipik olarak ne olacağı anahtar / değer çiftlerini ekleyebilmenizdir, ancak tüm haritayı tekrarlarsanız ve / veya "eksik" olduğunu tespit ederseniz yinelenen anahtar / değer çiftleriyle karşılaşabilirsiniz std::map::find()Haritada belirli bir anahtar / değer çiftini gerçekleştirmeye çalıştığınızda anahtar / değer çiftleri.


Diğer cevaplar gibi, bu aslında soruma cevap vermiyor, yine de teşekkürler.
Kiril Kirov

-3

begin () en küçük elemanı verebilir. Ancak uygulamaya bağlıdır. C ++ standardında belirtilmiş mi? Değilse, bu varsayımı yapmak tehlikelidir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.