Saat ini saya memiliki std::map<std::string,int>
yang menyimpan nilai integer ke pengenal string unik, dan saya mencari dengan string tersebut. Itu sebagian besar melakukan apa yang saya inginkan, kecuali untuk itu tidak melacak urutan penyisipan. Jadi ketika saya mengulang peta untuk mencetak nilai, mereka diurutkan sesuai dengan string; tetapi saya ingin mereka diurutkan menurut urutan penyisipan (pertama).
Saya berpikir untuk menggunakan a vector<pair<string,int>>
sebagai gantinya, tetapi saya perlu mencari string dan menaikkan nilai integer sekitar 10.000.000 kali, jadi saya tidak tahu apakah a std::vector
akan jauh lebih lambat.
Adakah cara untuk menggunakan std::map
atau adakah std
wadah lain yang lebih sesuai dengan kebutuhan saya?
[Saya menggunakan GCC 3.4, dan saya mungkin tidak memiliki lebih dari 50 pasang nilai di std::map
].
Terima kasih.
sumber
Jawaban:
Jika Anda hanya memiliki 50 nilai di std :: map Anda dapat menyalinnya ke std :: vector sebelum mencetak dan mengurutkan melalui std :: sort menggunakan functor yang sesuai.
Atau Anda bisa menggunakan boost :: multi_index . Ini memungkinkan untuk menggunakan beberapa indeks. Dalam kasus Anda, ini akan terlihat seperti berikut:
sumber
Anda bisa menggabungkan a
std::vector
denganstd::tr1::unordered_map
(tabel hash). Berikut tautan ke dokumentasi Boost untukunordered_map
. Anda dapat menggunakan vektor untuk melacak urutan penyisipan dan tabel hash untuk melakukan pencarian yang sering. Jika Anda melakukan ratusan ribu pencarian, perbedaan antara pencarian O (log n)std::map
dan O (1) untuk tabel hash mungkin signifikan.sumber
std::map
untuk bekerja sebagaimana mestinya (yaitu dengan menyortir sendiri saat Anda memasukkan), dan memiliki runtime yang cepat. (Saya membaca ini setelah menulis versi saya, di mana saya menggunakan std :: list!)Jaga agar tetap paralel
list<string> insertionOrder
.Ketika tiba waktunya untuk mencetak, lakukan iterasi pada daftar dan lakukan pencarian ke peta .
sumber
std::string_view
kunci peta yang mengacustd::string
padainsertionOrder
daftar. Hal ini untuk menghindari penyalinan tetapi Anda harus berhati-hati karenainsertionOrder
elemen - elemen tersebut hidup lebih lama dari kunci di peta yang merujuk padanya.Tessil memiliki implementasi yang sangat bagus dari peta yang dipesan (dan set) yang merupakan lisensi MIT. Anda dapat menemukannya di sini: peta-dipesan
Contoh peta
sumber
Jika Anda membutuhkan kedua strategi pencarian, Anda akan mendapatkan dua kontainer. Anda dapat menggunakan a
vector
dengan nilai aktual Andaint
, dan meletakkan a dimap< string, vector< T >::difference_type>
sebelahnya, mengembalikan indeks ke dalam vektor.Untuk menyelesaikan semua itu, Anda dapat merangkum keduanya dalam satu kelas.
Tapi saya yakin boost memiliki wadah dengan banyak indeks.
sumber
Apa yang Anda inginkan (tanpa menggunakan Boost) adalah apa yang saya sebut "hash yang dipesan", yang pada dasarnya adalah gabungan dari hash dan daftar tertaut dengan kunci string atau integer (atau keduanya pada saat yang sama). Hash terurut mempertahankan urutan elemen selama iterasi dengan kinerja hash yang absolut.
Saya telah menyusun pustaka cuplikan C ++ yang relatif baru yang mengisi apa yang saya lihat sebagai lubang dalam bahasa C ++ untuk pengembang pustaka C ++. Kesini:
https://github.com/cubiclesoft/cross-platform-cpp
Mengambil:
Jika data yang dikontrol pengguna akan ditempatkan ke dalam hash, Anda mungkin juga ingin:
Panggil itu:
Saya menemukan utas SO ini selama fase penelitian saya untuk melihat apakah sesuatu seperti OrderedHash sudah ada tanpa mengharuskan saya untuk mampir di perpustakaan besar. Aku kecewa. Jadi saya menulis sendiri. Dan sekarang saya sudah membagikannya.
sumber
Anda tidak dapat melakukannya dengan peta, tetapi Anda dapat menggunakan dua struktur yang terpisah - peta dan vektor dan membuatnya tetap sinkron - yaitu saat Anda menghapus dari peta, mencari dan menghapus elemen dari vektor. Atau Anda dapat membuat
map<string, pair<int,int>>
- dan pada pasangan Anda menyimpan ukuran () dari peta saat penyisipan untuk merekam posisi, bersama dengan nilai int, dan kemudian saat Anda mencetak, gunakan anggota posisi untuk mengurutkan.sumber
Cara lain untuk mengimplementasikannya adalah dengan a
map
alih - alih avector
. Saya akan menunjukkan kepada Anda pendekatan ini dan membahas perbedaannya:Buat saja kelas yang memiliki dua peta di belakang layar.
Anda kemudian dapat menampilkan iterator ke iterator
data_
dalam urutan yang benar. Cara Anda melakukannya adalah melalui iterasiinsertion_order_
, dan untuk setiap elemen yang Anda peroleh dari iterasi itu, lakukan pencariandata_
dengan nilai frominsertion_order_
Anda dapat menggunakan cara yang lebih efisien
hash_map
untuk penyisipan_order karena Anda tidak peduli tentang pengulangan secara langsunginsertion_order_
.Untuk melakukan penyisipan, Anda dapat memiliki metode seperti ini:
Ada banyak cara untuk membuat desain lebih baik dan mengkhawatirkan kinerja, tetapi ini adalah kerangka yang baik untuk membantu Anda mulai menerapkan fungsi ini sendiri. Anda dapat membuatnya menjadi template, dan Anda mungkin benar-benar menyimpan pasangan sebagai nilai dalam data_ sehingga Anda dapat dengan mudah mereferensikan entri di insertion_order_. Tapi saya biarkan masalah desain ini sebagai latihan :-).
Pembaruan : Saya kira saya harus mengatakan sesuatu tentang efisiensi penggunaan peta vs. vektor untuk penyisipan_order_
Mungkin jika Anda tidak akan menggunakan penghapusan sebanyak mungkin, Anda harus menggunakan pendekatan vektor. Pendekatan peta akan lebih baik jika Anda mendukung urutan yang berbeda (seperti prioritas) daripada urutan penyisipan.
sumber
Berikut adalah solusi yang hanya membutuhkan pustaka template standar tanpa menggunakan multiindex boost:
Anda dapat menggunakan
std::map<std::string,int>;
danvector <data>;
di mana di peta Anda menyimpan indeks lokasi data dalam vektor dan vektor menyimpan data dalam urutan penyisipan. Di sini akses ke data memiliki kompleksitas O (log n). menampilkan data dalam urutan penyisipan memiliki kompleksitas O (n). penyisipan data memiliki kompleksitas O (log n).Sebagai contoh:
sumber
Ini agak terkait dengan jawaban Faisal. Anda bisa membuat kelas pembungkus di sekitar peta dan vektor dan dengan mudah membuatnya tetap sinkron. Enkapsulasi yang tepat akan membiarkan Anda mengontrol metode akses dan karenanya wadah mana yang akan digunakan ... vektor atau peta. Ini menghindari penggunaan Boost atau semacamnya.
sumber
Satu hal yang perlu Anda pertimbangkan adalah jumlah kecil elemen data yang Anda gunakan. Mungkin saja akan lebih cepat menggunakan vektor saja. Ada beberapa overhead dalam peta yang dapat menyebabkan lebih mahal untuk melakukan pencarian dalam kumpulan data kecil daripada vektor yang lebih sederhana. Jadi, jika Anda tahu bahwa Anda akan selalu menggunakan elemen dengan jumlah yang sama, lakukan beberapa pembandingan dan lihat apakah kinerja peta dan vektor sesuai dengan yang Anda pikirkan. Anda mungkin menemukan pencarian dalam vektor dengan hanya 50 elemen yang hampir sama dengan peta.
sumber
// Seharusnya seperti pria ini!
// Ini menjaga kompleksitas penyisipan adalah O (logN) dan penghapusan juga O (logN).
sumber
Gunakan
boost::multi_index
dengan peta dan daftar indeks.sumber
Peta pasangan (str, int) dan int statis yang bertambah saat menyisipkan pasangan indeks data. Letakkan di struct yang dapat mengembalikan int val statis dengan anggota index () mungkin?
sumber