ลำดับของการวนซ้ำผ่านแผนที่ std :: เป็นที่รู้จัก (และรับประกันโดยมาตรฐาน) หรือไม่


158

สิ่งที่ฉันหมายถึงคือ - เรารู้ว่าstd::mapองค์ประกอบของเรียงตามคีย์ สมมุติว่ากุญแจนั้นเป็นจำนวนเต็ม หากฉันซ้ำจากstd::map::begin()การstd::map::end()ใช้ a forการรับประกันมาตรฐานจะให้ฉันทำซ้ำตามลำดับผ่านองค์ประกอบที่มีคีย์เรียงตามลำดับจากน้อยไปหามากหรือไม่


ตัวอย่าง:

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

สิ่งนี้รับประกันว่าจะพิมพ์234หรือมีการกำหนดการใช้งานหรือไม่


เหตุผลชีวิตจริง: ฉันมีstd::mapกับintคีย์ ในสถานการณ์ที่หายากมากฉันต้องการวนซ้ำองค์ประกอบทั้งหมดด้วยคีย์มากกว่าintค่าที่เป็นรูปธรรม ใช่ดูเหมือนstd::vectorจะเป็นตัวเลือกที่ดีกว่า แต่สังเกต "สถานการณ์ที่หายากมาก" ของฉัน


แก้ไข : ฉันรู้ว่าองค์ประกอบของstd::mapเรียงลำดับ .. ไม่จำเป็นต้องชี้ให้เห็น (สำหรับคำตอบส่วนใหญ่ที่นี่) ฉันยังเขียนไว้ในคำถามของฉัน
ฉันถูกถามเกี่ยวกับตัววนซ้ำและลำดับเมื่อฉันวนซ้ำผ่านคอนเทนเนอร์ ขอบคุณ @Kerrek SB สำหรับคำตอบ


6
ในกรณีที่คุณไม่ทราบ: ในชีวิตจริงของคุณใช้คุณสามารถใช้map::upper_boundเพื่อหาจุดที่จะเริ่มทำซ้ำ
Steve Jessop

ฉันรู้สิ่งนี้และรู้สถานที่ที่แน่นอนที่ฉันจะเริ่มต้นทำซ้ำ ฉันเพิ่งเดินถ้ารับประกันการสั่งซื้อ
คิริลคิรอฟ

เวกเตอร์ที่กระจัดกระจายจะไม่สมเหตุสมผลถ้าปุ่มของคุณ (ดัชนีตัวเลข) แตกต่างกันอย่างมากในกระดาน ฉันกำลังใช้โซลูชันที่คล้ายกันซึ่งดัชนีตัวเลขแสดงพิกัด y คาร์ทีเซียนในพื้นที่สามมิติ การใช้เวกเตอร์ในสถานการณ์นี้จะเพิ่มพื้นที่หน่วยความจำของฉันเป็นกิกะไบต์ ดังนั้นฉันไม่คิดว่าเวกเตอร์เป็นยาครอบจักรวาลที่นี่ห่างไกลจากมัน
Jonathan Neufeld

ฉันไม่เข้าใจคำถามและฉันจะอธิบายว่าทำไมผ่านการทดสอบความคิด หากคุณรู้อยู่แล้วว่าองค์ประกอบนั้นได้รับคำสั่งแล้วการวนซ้ำจะไม่เป็นอย่างไร การสั่งซื้อหมายถึงอะไรถ้าไม่ได้ใช้กับการทำซ้ำ มีกรณีอื่นอีกบ้างที่คำสั่งซื้อตรวจจับได้ ฯลฯ (คำตอบที่ได้รับจากKonstantin .)
underscore_d

คำตอบ:


176

ใช่รับประกัน ยิ่งกว่านั้น*begin()ให้องค์ประกอบที่เล็กที่สุดและ*rbegin()ใหญ่ที่สุดตามที่กำหนดโดยตัวดำเนินการเปรียบเทียบและค่าคีย์สองค่าaและbนิพจน์ที่!compare(a,b) && !compare(b,a)เป็นจริงถือว่าเท่ากัน ฟังก์ชันเปรียบเทียบค่าเริ่มต้นคือstd::less<K>ฟังก์ชั่นการเปรียบเทียบค่าเริ่มต้นคือ

การสั่งซื้อไม่ใช่คุณสมบัติโบนัสนำโชค แต่เป็นการจัดลำดับความสำคัญพื้นฐานของโครงสร้างข้อมูลเนื่องจากการเรียงลำดับใช้เพื่อกำหนดว่าเมื่อใดที่คีย์สองปุ่มเหมือนกัน (ตามกฎข้างต้น) และทำการค้นหาอย่างมีประสิทธิภาพ ค้นหาซึ่งมีความซับซ้อนลอการิทึมในจำนวนองค์ประกอบ)


std :: map ถูกนำไปใช้โดยใช้ binary trees ดังนั้นในทางเทคนิคแล้วไม่มีการค้นหาแบบไบนารี
jupp0r

11
@ jupp0r: การจัดโครงสร้างช่วงเป็นแผนผังการค้นหาแบบไบนารีเป็นวิธีการเฉพาะในการใช้การค้นหาแบบไบนารีผ่านช่วง "การค้นหาแบบไบนารี่" เป็นแนวคิดที่เป็นนามธรรมมากกว่าการใช้งานแบบเฉพาะ ไม่สำคัญว่าคุณจะกระโดดข้ามออฟเซ็ตไปยังอาร์เรย์หรือติดตามโหนดลิงก์ นี่เป็นวิธีการเฉพาะของ "การแบ่งช่วง"
Kerrek SB

1
ฉันรู้ว่านี่เป็นโพสต์เก่า แต่เพื่อให้ชัดเจนว่า "การค้นหาที่มีประสิทธิภาพ" นั้นสัมพันธ์กัน ในทางเทคนิคแล้วstd::unordered_mapเวลาค้นหา O (1) จะมีประสิทธิภาพมากขึ้น ข้อได้เปรียบของการstd::mapสั่งซื้อที่สำคัญคือ แต่ไม่ได้ค้นหา
Adam Johnston

42

สิ่งนี้รับประกันโดยข้อกำหนดของ Associative container ในมาตรฐาน C ++ เช่นดู 23.2.4 / 10 ใน C ++ 11:

คุณสมบัติพื้นฐานของตัววนซ้ำของคอนเทนเนอร์แบบเชื่อมโยงคือคุณสมบัติเหล่านั้น
วนซ้ำในคอนเทนเนอร์โดยเรียงตามลำดับที่ไม่ลดลงของคีย์
ที่ไม่ใช่จากมากไปน้อยถูกกำหนดโดยการเปรียบเทียบที่ใช้ในการสร้างพวกเขา
สำหรับผู้ทำซ้ำสองคนที่ปฏิเสธไม่ได้ทั้งตัวฉันและ j นั่นคือระยะทางจาก i ถึง j คือ
บวก,
  value_comp (* j, * i) == false

และ 23.2.4 / 11

สำหรับภาชนะบรรจุที่เชื่อมโยงกับกุญแจที่ไม่ซ้ำกันสภาพที่แข็งแกร่งจะถือ
  value_comp (* i, * j)! = false

32

ฉันคิดว่ามีความสับสนในโครงสร้างข้อมูล

ในภาษาส่วนใหญ่ a mapเป็นเพียง AssociativeContainer: มันแมปกุญแจกับค่า ในภาษา "ใหม่กว่า" สิ่งนี้สามารถทำได้โดยใช้แผนที่แฮชดังนั้นจึงไม่รับประกันการสั่งซื้อ

อย่างไรก็ตามใน C ++ สิ่งนี้ไม่เป็นเช่นนั้น:

  • std::mapเป็นคอนเทนเนอร์ที่จัดเรียง
  • std::unordered_map เป็นคอนเทนเนอร์ที่เชื่อมโยงกับตารางแฮชที่นำมาใช้ใน C ++ 11

ดังนั้นเพื่อชี้แจงการรับประกันในการสั่งซื้อ

ใน C ++ 03:

  • std::set, std::multiset, std::mapและstd::multimapมีการรับประกันที่จะสั่งตามคีย์ (และเกณฑ์ให้มาด้วย)
  • ในstd::multisetและstd::multimapมาตรฐานไม่ได้กำหนดการรับประกันคำสั่งซื้อใด ๆ ในองค์ประกอบที่เทียบเท่า (กล่าวคือผู้ที่เปรียบเทียบเท่ากัน)

ใน C ++ 11:

  • std::set, std::multiset, std::mapและstd::multimapมีการรับประกันที่จะสั่งตามคีย์ (และเกณฑ์ให้มาด้วย)
  • ในstd::multisetและstd::multimapมาตรฐานกำหนดว่าองค์ประกอบที่เทียบเท่า (ที่เปรียบเทียบเท่ากัน) ได้รับคำสั่งตามลำดับการแทรก (แทรกครั้งแรกก่อน)
  • std::unordered_*ตู้คอนเทนเนอร์เป็นชื่อที่บ่งบอกถึงไม่ได้รับคำสั่ง ที่สะดุดตาที่สุดลำดับขององค์ประกอบอาจเปลี่ยนแปลงเมื่อมีการปรับเปลี่ยนคอนเทนเนอร์ (ตามการแทรก / การลบ)

เมื่อ Standard บอกว่ามีการเรียงลำดับองค์ประกอบก็หมายความว่า:

  • เมื่อวนซ้ำคุณจะเห็นองค์ประกอบตามลำดับที่กำหนด
  • เมื่อวนซ้ำคุณจะเห็นองค์ประกอบตามลำดับที่ตรงกันข้าม

ฉันหวังว่าสิ่งนี้จะช่วยขจัดความสับสน


สิ่งนี้ไม่มีอะไรเกี่ยวข้องกับคำถามของฉันขอโทษ :) ฉันรู้ว่าได้รับคำสั่งซื้อใดและอันไหน - ไม่ และฉันขอคำสั่งเมื่อฉันวนซ้ำองค์ประกอบ
คิริลคิรอฟ

10
@KirilKirov: ความหมายของคอนเทนเนอร์ที่เชื่อมโยงที่ได้รับคำสั่งคือเมื่อทำการวนซ้ำองค์ประกอบจะถูกจัดเรียง
Matthieu M.

ดีฉันคิดว่าคุณกำลังขวา แต่ผมไม่ทราบว่าและนั่นคือสิ่งที่ผมถาม :)
Kiril คิรอฟ

4

สิ่งนี้รับประกันว่าจะพิมพ์ 234 หรือมีการกำหนดการใช้งานหรือไม่

ใช่std::mapเป็นคอนเทนเนอร์ที่เรียงลำดับแล้วสั่งโดยKeyพร้อมด้วยที่ให้Comparatorมา ดังนั้นจึงรับประกันได้

ฉันต้องการวนซ้ำทุกองค์ประกอบด้วยคีย์มากกว่าค่า int ที่เป็นรูปธรรม

นั่นเป็นไปได้อย่างแน่นอน


3

ใช่ ... องค์ประกอบใน a std::mapมีการจัดลำดับอ่อนอย่างเข้มงวดหมายความว่าองค์ประกอบจะประกอบด้วยชุด (กล่าวคือจะไม่มีการทำซ้ำของคีย์ที่ "เท่าเทียมกัน") และความเท่าเทียมกันถูกกำหนดโดยการทดสอบใด ๆ ปุ่มสองปุ่ม A และ B, ถ้าคีย์ A ไม่น้อยกว่าปุ่ม B และ B ไม่น้อยกว่า A ดังนั้นคีย์ A เท่ากับคีย์ B

ดังที่กล่าวไว้ว่าคุณไม่สามารถจัดเรียงองค์ประกอบของ a std::mapหากการจัดลำดับอ่อนสำหรับประเภทนั้นไม่ชัดเจน (ในกรณีของคุณซึ่งคุณใช้จำนวนเต็มเป็นคีย์ชนิดซึ่งไม่ใช่ปัญหา) คุณต้องสามารถกำหนดการดำเนินการที่กำหนดลำดับรวมของประเภทที่คุณใช้สำหรับคีย์ในของคุณstd::mapมิฉะนั้นคุณจะมีคำสั่งบางส่วนสำหรับองค์ประกอบหรือโพสต์ของคุณซึ่งมีคุณสมบัติที่ A อาจไม่สามารถเทียบเคียงได้ B. โดยทั่วไปแล้วสิ่งที่จะเกิดขึ้นในสถานการณ์นี้คือคุณจะสามารถแทรกคู่คีย์ / ค่าได้ แต่คุณอาจลงท้ายด้วยคู่คีย์ / ค่าที่ซ้ำกันหากคุณวนซ้ำทั่วทั้งแผนที่และ / หรือตรวจจับ "หายไป" คู่ของคีย์ / ค่าเมื่อคุณพยายามดำเนินการคู่std::map::find()ของคีย์ / ค่าเฉพาะในแผนที่


ในฐานะที่เป็นคำตอบอื่น ๆ นี้ไม่ได้ตอบคำถามของฉันจริงขอบคุณ
คิริลคิรอฟ

-3

เริ่มต้น () อาจให้องค์ประกอบที่เล็กที่สุด แต่มันขึ้นอยู่กับการใช้งาน มันระบุไว้ในมาตรฐาน C ++ หรือไม่ ถ้าไม่เช่นนั้นมันเป็นอันตรายที่จะทำให้สมมติฐานนี้

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.