Là thứ tự lặp qua std :: map đã biết (và được đảm bảo theo tiêu chuẩn)?


158

Ý tôi là - chúng ta biết rằng các std::mapyếu tố của được sắp xếp theo các phím. Vì vậy, giả sử các khóa là số nguyên. Nếu tôi lặp lại từ std::map::begin()việc std::map::end()sử dụng a for, liệu có đảm bảo tiêu chuẩn rằng tôi sẽ lặp lại thông qua các phần tử với các khóa, được sắp xếp theo thứ tự tăng dần không?


Thí dụ:

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

Điều này có được đảm bảo để in 234hoặc nó được thực hiện được xác định?


Lý do thực tế cuộc sống: Tôi có một std::mapvới intcác phím. Trong các tình huống rất hiếm, tôi muốn lặp lại qua tất cả các yếu tố, với khóa, lớn hơn một intgiá trị cụ thể . Đúng, có vẻ như std::vectorsẽ là lựa chọn tốt hơn, nhưng hãy chú ý "những tình huống rất hiếm" của tôi.


EDIT : Tôi biết, các yếu tố std::mapđược sắp xếp .. không cần phải chỉ ra (đối với hầu hết các câu trả lời ở đây). Tôi thậm chí đã viết nó trong câu hỏi của tôi.
Tôi đã hỏi về các trình vòng lặp và thứ tự khi tôi lặp qua một container. Cảm ơn @Kerrek SB đã trả lời.


6
Trong trường hợp bạn không biết: trong cuộc sống thực của bạn, bạn có thể sử dụng map::upper_boundđể tìm điểm bắt đầu lặp lại.
Steve Jessop

Tôi biết điều này và tôi biết chính xác nơi tôi sẽ bắt đầu lặp lại. Tôi chỉ đi lang thang nếu đơn hàng được đảm bảo.
Kiril Kirov

Một vectơ thưa thớt sẽ không hợp lý nếu các phím của bạn (chỉ số số) thay đổi rất lớn trên bảng. Tôi đang sử dụng một giải pháp tương tự mà chỉ số số biểu thị tọa độ y của Cartesian trong không gian 3 chiều. Sử dụng một vectơ trong kịch bản này sẽ tăng dung lượng bộ nhớ của tôi lên hàng gigabyte. Vì vậy, tôi không nghĩ rằng vectơ là thuốc chữa bách bệnh ở đây, cách xa nó.
Jonathan Neufeld

Tôi không hiểu câu hỏi và tôi sẽ giải thích tại sao thông qua một thử nghiệm suy nghĩ. Nếu bạn đã biết rằng các phần tử được sắp xếp, làm thế nào lặp lại không được? Việc đặt hàng thậm chí có nghĩa là gì, nếu nó không áp dụng cho phép lặp? Những trường hợp khác là có vấn đề trật tự, có thể phát hiện, vv? (Câu trả lời được đưa ra bởi Konstantin .)
underscore_d

Câu trả lời:


176

Vâng, điều đó được đảm bảo. Hơn nữa, *begin()cung cấp cho bạn phần tử nhỏ nhất và *rbegin()lớn nhất, như được xác định bởi toán tử so sánh và hai giá trị chính abbiểu thức !compare(a,b) && !compare(b,a)là đúng được coi là bằng nhau. Hàm so sánh mặc định là std::less<K>.

Thứ tự không phải là một tính năng thưởng may mắn, nhưng đúng hơn, nó là một khía cạnh cơ bản của cấu trúc dữ liệu, vì thứ tự được sử dụng để xác định khi nào hai khóa giống nhau (theo quy tắc trên) và để thực hiện tra cứu hiệu quả (về cơ bản là nhị phân tìm kiếm, có độ phức tạp logarit trong số lượng phần tử).


std :: map được triển khai bằng cây nhị phân, vì vậy về mặt kỹ thuật không có tìm kiếm nhị phân nào được thực hiện.
jupp0r

11
@ jupp0r: Cấu trúc một phạm vi dưới dạng cây tìm kiếm nhị phân là một phương pháp cụ thể để thực hiện tìm kiếm nhị phân thông qua phạm vi. "Tìm kiếm nhị phân" là một khái niệm trừu tượng hơn là một triển khai cụ thể. Không quan trọng bạn nhảy qua các mảng vào một mảng hay theo các nút liên kết; đó chỉ là những cách cụ thể để "chia đôi phạm vi".
Kerrek SB

1
Tôi biết đây là một bài viết cũ, nhưng để rõ ràng "tra cứu hiệu quả" là tương đối. Về mặt kỹ thuật, std::unordered_mapthời gian tra cứu hiệu quả hơn của O (1). Ưu điểm của std::maplà đặt hàng chính, nhưng không tra cứu.
Adam Johnston

42

Điều này được đảm bảo bởi các yêu cầu liên kết container trong tiêu chuẩn C ++. Ví dụ, xem 23.2.4 / 10 trong C ++ 11:

Thuộc tính cơ bản của các vòng lặp của container kết hợp là chúng
Lặp lại qua các thùng chứa theo thứ tự các phím không giảm dần trong đó
không giảm dần được xác định bởi so sánh đã được sử dụng để xây dựng chúng.
Đối với bất kỳ hai trình lặp lặp có thể điều chỉnh i và j sao cho khoảng cách từ i đến j là
tích cực,
  value_comp (* j, * i) == sai

và 23.2.4 / 11

Đối với các thùng chứa kết hợp với các phím duy nhất, điều kiện mạnh hơn giữ,
  value_comp (* i, * j)! = sai.

32

Tôi nghĩ rằng có một sự nhầm lẫn trong cấu trúc dữ liệu.

Trong hầu hết các ngôn ngữ, a mapchỉ đơn giản là AssociativeContainer: nó ánh xạ khóa tới một giá trị. Trong các ngôn ngữ "mới hơn", điều này thường đạt được bằng cách sử dụng bản đồ băm, do đó không có đơn hàng nào được đảm bảo.

Tuy nhiên, trong C ++, đây không phải là như vậy:

  • std::maplà một container kết hợp được sắp xếp
  • std::unordered_map là một thùng chứa kết hợp dựa trên bảng băm được giới thiệu trong C ++ 11

Vì vậy, để làm rõ các đảm bảo về đặt hàng.

Trong C ++ 03:

  • std::set, std::multiset, std::mapstd::multimapđược đảm bảo để được sắp xếp theo các phím (và tiêu chí cung cấp)
  • trong std::multisetstd::multimap, tiêu chuẩn không áp đặt bất kỳ sự đảm bảo trật tự nào đối với các yếu tố tương đương (nghĩa là các yếu tố so sánh bằng nhau)

Trong C ++ 11:

  • std::set, std::multiset, std::mapstd::multimapđược đảm bảo để được sắp xếp theo các phím (và tiêu chí cung cấp)
  • trong std::multisetstd::multimap, Tiêu chuẩn áp đặt rằng các yếu tố tương đương (những yếu tố so sánh bằng nhau) được sắp xếp theo thứ tự chèn (đầu tiên được chèn trước)
  • std::unordered_*container, như tên ngụ ý, không được đặt hàng. Đáng chú ý nhất, thứ tự của các yếu tố có thể thay đổi khi container được sửa đổi (khi chèn / xóa).

Khi Tiêu chuẩn nói rằng các phần tử được sắp xếp theo cách, điều đó có nghĩa là:

  • Khi lặp lại, bạn sẽ thấy các phần tử theo thứ tự được xác định
  • Khi lặp lại, bạn thấy các phần tử theo thứ tự ngược lại

Tôi hy vọng điều này sẽ làm sáng tỏ bất kỳ sự nhầm lẫn.


Điều này không liên quan gì đến câu hỏi của tôi, xin lỗi :) Tôi biết cái nào được đặt hàng, và cái nào - không. Và tôi đang yêu cầu thứ tự khi tôi lặp qua các yếu tố.
Kiril Kirov

10
@KirilKirov: tốt, định nghĩa của một container kết hợp được đặt hàng là khi lặp qua nó, các phần tử được sắp xếp.
Matthieu M.

Chà, tôi đoán là bạn đúng, nhưng tôi không biết điều đó và đó chính xác là những gì tôi đã hỏi :)
Kiril Kirov

4

Điều này có được đảm bảo để in 234 hoặc thực hiện được xác định không?

Có, std::maplà một container được sắp xếp , được sắp xếp theo thứ tự được Keycung cấp Comparator. Vì vậy, nó được đảm bảo.

Tôi muốn đi lặp lại qua tất cả các yếu tố, với khóa, lớn hơn một giá trị int cụ thể.

Điều đó là chắc chắn có thể.


3

Có ... các phần tử trong một std::mapthứ tự yếu nghiêm ngặt, nghĩa là các phần tử sẽ được tạo thành từ một tập hợp (nghĩa là sẽ không có sự lặp lại của các khóa "bằng nhau") và tính bằng nhau được xác định bằng cách kiểm tra trên bất kỳ hai khóa A và B, nếu khóa A không nhỏ hơn khóa B và B không nhỏ hơn A, thì khóa A bằng với khóa B.

Điều đó đang được nói, bạn không thể sắp xếp chính xác các yếu tố của a std::mapnếu thứ tự yếu cho loại đó không rõ ràng (trong trường hợp của bạn, trong đó bạn đang sử dụng số nguyên làm loại khóa, đó không phải là vấn đề). Bạn phải có thể xác định một thao tác xác định tổng thứ tự cho loại bạn đang sử dụng cho các khóa trong std::map, nếu không, bạn sẽ chỉ có một phần thứ tự cho các phần tử của bạn, hoặc poset, có thuộc tính mà A không thể so sánh được với B. Điều thường xảy ra trong kịch bản này là bạn sẽ có thể chèn các cặp khóa / giá trị, nhưng bạn có thể kết thúc bằng các cặp khóa / giá trị trùng lặp nếu bạn lặp qua toàn bộ bản đồ và / hoặc phát hiện "mất tích" cặp khóa / giá trị khi bạn cố gắng thực hiện một std::map::find()cặp khóa / giá trị cụ thể trong bản đồ.


Như các câu trả lời khác, điều này thực sự không trả lời câu hỏi của tôi, dù sao cũng cảm ơn.
Kiril Kirov

-3

started () có thể cho phần tử nhỏ nhất. Nhưng đó là thực hiện phụ thuộc. Được chỉ định trong tiêu chuẩn C ++? Nếu không, thì thật nguy hiểm khi đưa ra giả định này.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.