Apakah perpustakaan standar C++ memiliki kumpulan yang diurutkan berdasarkan urutan penyisipan?

Apakah pustaka standar C++ memiliki struktur data "kumpulan terurut"? Yang saya maksud dengan set terurut adalah sesuatu yang persis sama dengan std::set biasa tetapi mengingat urutan penambahan item ke dalamnya.

Jika tidak, apa cara terbaik untuk mensimulasikannya? Saya tahu Anda dapat melakukan sesuatu seperti memiliki satu set pasangan dengan setiap pasangan menyimpan nomor yang ditambahkan dan nilai sebenarnya, tetapi saya tidak ingin melewati rintangan jika ada solusi yang lebih sederhana.


person Seth Carnegie    schedule 18.10.2011    source sumber
comment
Jadi Anda ingin dapat mengaksesnya dengan cepat baik secara terurut maupun dalam urutan penyisipan?   -  person Cascabel    schedule 18.10.2011
comment
Apa tepatnya karakteristik set lain yang Anda minati? Keunikan? Kinerja penghapusan?   -  person Robᵩ    schedule 18.10.2011
comment
@Jefromi Saya ingin segera mengetahui apakah suatu item ada di set dan mengulanginya dalam urutan yang disisipkan jika memungkinkan.   -  person Seth Carnegie    schedule 18.10.2011
comment
Apa yang Anda gambarkan adalah skenario tepat yang dibuat untuk Boost.MultiIndex (lihat jawaban @KerrekSB).   -  person ildjarn    schedule 18.10.2011
comment
@Rob keunikan dan kecepatan memeriksa apakah ada sesuatu yang ada di set atau tidak.   -  person Seth Carnegie    schedule 18.10.2011


Jawaban (6)


Tidak ada struktur data tunggal dan homogen yang memiliki sifat ini, karena sifatnya yang berurutan (yaitu elemen disusun dalam urutan penyisipan) atau asosiatif (elemen disusun dalam urutan tertentu bergantung pada nilainya).

Pendekatan terbaik dan bersih mungkin seperti Boost.MultiIndex, yang memungkinkan Anda menambahkan beberapa indeks, atau "tampilan", pada sebuah wadah, sehingga Anda dapat memiliki indeks yang berurutan dan terurut.

person Kerrek SB    schedule 18.10.2011
comment
+1 untuk merekomendasikan Boost.MultiIndex -- ini benar-benar solusi terbaik untuk pertanyaan semacam ini. - person ildjarn; 18.10.2011
comment
Anda bisa menggunakan lambda untuk fungsi perbandingan saat menginisialisasi set. Dia menginginkan keunikan elemen tetapi dalam urutan penyisipan. Saya pikir ini mungkin bisa dilakukan? Saya tidak mengerti mengapa hal ini dilarang. - person dylan; 16.09.2017
comment
Mungkin menggunakan vektor dan algoritma unik untuk menghapus elemen non unik. Atau apakah ini lebih lambat dibandingkan metode lainnya? Saya kira algoritma pencarian akan lebih lambat daripada sekadar menyimpan indeks. - person dylan; 16.09.2017
comment
@dylan: Ya, tapi itu bukan satu wadah. Anda dapat membuat perilaku apa pun yang dapat dibayangkan dengan array dan algoritme (memori komputer hanyalah satu array besar)... - person Kerrek SB; 16.09.2017

Daripada membuat std::set dengan tipe apa pun yang Anda gunakan, mengapa tidak memberikannya std::pair objek dan indeks yang bertambah pada setiap penyisipan?

person pg1989    schedule 18.10.2011
comment
Itu akan berhasil, jika Anda berhati-hati saat memasukkan nilai yang ada, dan jika Anda memiliki kebijakan bagaimana menemukan indeks terbesar dalam waktu yang konstan. Mungkin std::map<T, unsigned int> akan sedikit lebih elegan, karena tipe nilainya sudah berpasangan (dan Anda mendapatkan elemen yang dipetakan bisa berubah). - person Kerrek SB; 18.10.2011
comment
@SethCarnegie: Ingat, Anda masih harus dapat menemukan indeks tertinggi saat ini, dan itu mungkin tidak dapat dilakukan dalam waktu yang konstan, atau bahkan logaritmik. - person Kerrek SB; 18.10.2011
comment
@Kerrek kenapa? Jika Anda memulai dari 0 (yaitu saya), Anda dapat menggunakan map::size untuk mencari indeks terbesar bukan? - person Seth Carnegie; 18.10.2011
comment
@SethCarnegie: Ya, memang, Anda bisa menggunakan size(), saya belum memikirkannya! - person Kerrek SB; 18.10.2011
comment
Jawaban Kerrek yang lain secara umum masih lebih baik, karena Boost.MultiIndex akan memungkinkan Anda secara efisien mengakses penampung yang diindeks berdasarkan urutan penyisipan. Seperti yang terjadi pada map<T, unsigned int> ini, ini adalah operasi O(n) untuk menemukan elemen dengan indeks tertentu. Iterasi dalam urutan penyisipan adalah O(n^2) tanpa memori tambahan, atau O(n log n) dengan O(n) memori tambahan jika Anda menyalin seluruh lot ke dalam array dan mengurutkannya sebelum melakukan iterasi. Mungkin baik-baik saja untuk tujuan Seth, tapi cukup membatasi... - person Steve Jessop; 18.10.2011

Tidak.

Wadah seperti itu mungkin memerlukan dua iterator yang berbeda, satu untuk melakukan iterasi dalam urutan yang ditentukan oleh urutan penambahan, dan satu lagi untuk melakukan iterasi dalam urutan set biasa. Tidak ada hal semacam itu di perpustakaan standar.

Salah satu opsi untuk mensimulasikannya adalah dengan memiliki set dari beberapa tipe yang berisi node daftar tertaut yang mengganggu selain data aktual yang Anda pedulikan. Setelah menambahkan elemen ke set, tambahkan elemen tersebut ke daftar tertaut. Sebelum menghapus elemen dari set, hapus elemen tersebut dari daftar tertaut. Ini dijamin OK, karena pointer ke elemen set tidak dibatalkan oleh operasi apa pun selain menghapus elemen tersebut.

person Steve Jessop    schedule 18.10.2011
comment
Ah, sayang sekali. Apa yang Anda rekomendasikan untuk dilakukan? - person Seth Carnegie; 18.10.2011

Saya pikir jawabannya cukup sederhana, gabungkan set dengan struktur lain yang dapat diulang (misalnya, antrian). Jika Anda ingin mengulangi himpunan sesuai urutan penyisipan elemen, dorong elemen ke dalam antrian terlebih dahulu, lakukan pekerjaan Anda pada elemen depan, lalu keluarkan, masukkan ke dalam himpunan.

person Jun    schedule 21.03.2014

[Penafian: Saya telah memberikan jawaban serupa untuk pertanyaan ini sudah]

Jika Anda dapat menggunakan Boost, solusi yang sangat mudah adalah dengan menggunakan pustaka khusus header Boost.Bimap (peta dua arah).

Pertimbangkan contoh program berikut yang akan menampilkan beberapa entri dummy dalam urutan penyisipan (coba di sini ):

#include <iostream>
#include <string>
#include <type_traits>
#include <boost/bimap.hpp>

using namespace std::string_literals;

template <typename T>
void insertByOrder(boost::bimap<T, size_t>& mymap, const T& element) {
  using pos = typename std::remove_reference<decltype(mymap)>::type::value_type;
  // We use size() as index, therefore indexing the elements with 0, 1, ...
  mymap.insert(pos(element, mymap.size()));
}

int main() {
  boost::bimap<std::string, size_t> mymap;

  insertByOrder(mymap, "stack"s);
  insertByOrder(mymap, "overflow"s);

  // Iterate over right map view (integers) in sorted order
  for (const auto& rit : mymap.right) {
    std::cout << rit.first << " -> " << rit.second << std::endl;
  }
}

Alias ​​tipe funky di insertByOrder() diperlukan untuk menyisipkan elemen ke dalam boost::bimap di baris berikut (lihat dokumentasi referensi).

person andreee    schedule 03.05.2019

Ya, itu disebut vektor atau daftar (atau array). Cukup tambahkan ke vektor untuk menambahkan elemen ke set.

person Lie Ryan    schedule 18.10.2011
comment
Ya, tapi semua itu memungkinkan adanya elemen yang berlebihan, yang kemungkinan besar adalah apa yang coba dihindari oleh OP. - person pg1989; 18.10.2011
comment
pg1989 benar, saya tidak ingin elemen duplikat dan saya tidak ingin melakukan pencarian linier pada array untuk memeriksanya. - person Seth Carnegie; 18.10.2011