unordered_map untuk menemukan indeks array

Saya ingin mencari indeks suatu himpunan secara efisien. Saya menggunakan unordered_map dan membuat peta terbalik seperti ini

std::unordered_map <int, int> myHash (size); 
Int i = 0;
for (it = someSet.begin(); it != someSet.end(); it++)
{
    myHash.insert({*it , i++});
 }

Ini berfungsi tetapi tidak efisien. Saya melakukan ini sehingga kapan pun saya membutuhkan indeks, saya dapat mengaksesnya O(1). Analisis kinerja menunjukkan kepada saya bahwa bagian ini menjadi hotspot kode saya.

VTune memberi tahu saya bahwa operator new adalah hotspot saya. Saya kira ada sesuatu yang terjadi di dalam unordered_map. Menurut saya kasus ini harus ditangani secara efisien. Saya belum dapat menemukan cara yang baik. Apakah ada solusi yang lebih baik? konstruktor yang benar? Mungkin saya harus menyampaikan lebih banyak info ke konstruktor. Saya mencari daftar inisialisasi tetapi bukan itu yang saya inginkan.

Pembaruan: Izinkan saya menambahkan beberapa informasi lebih lanjut. Himpunannya tidak terlalu penting; Saya menyimpan set ke dalam array (diurutkan). Nanti saya perlu mencari indeks nilai yang unik. Saya bisa melakukannya di logn tetapi tidak cukup cepat. Itu sebabnya saya memutuskan untuk menggunakan hash. Ukuran himpunan (kolom submatriks) tidak berubah setelah titik ini.

Ini muncul dari perhitungan matriks renggang yang saya perlukan untuk mencari indeks submatriks dalam matriks yang lebih besar. Oleh karena itu ukuran dan pola pencarian bergantung pada matriks masukan. Ini berfungsi dengan baik pada masalah yang lebih kecil. Saya bisa menggunakan tabel pencarian tetapi ketika saya berencana melakukannya secara paralel, tabel pencarian untuk setiap thread bisa mahal. Saya memiliki ukuran hash yang tepat pada saat pembuatan. Saya pikir dengan mengirimkannya ke konstruktor itu berhenti mengalokasikan ulang. Saya benar-benar tidak mengerti mengapa realokasi sebanyak ini.


person Aznaveh    schedule 30.10.2020    source sumber
comment
Int? Maksudmu int?   -  person tadman    schedule 31.10.2020
comment
Berapa banyak elemen yang Anda konversi? Berapa banyak pencarian yang Anda lakukan? Biaya pembuatan tabel pencarian mungkin melebihi penghematan yang Anda dapatkan, jadi ini mungkin merupakan optimasi yang salah. Ada beberapa nilai ambang batas di mana jumlah elemen › N dan jumlah pencarian › M memberikan hasil positif, namun di bawah nilai tersebut sebenarnya negatif.   -  person tadman    schedule 31.10.2020
comment
@tadman Saya baru saja menyalin kode saya dan menyederhanakannya di sini. Lupa mengubah bagian ini. Lagipula tidak penting. Int adalah int yang panjang   -  person Aznaveh    schedule 31.10.2020
comment
@tadman Ini adalah bagian dari proyek yang lebih besar. ini berfungsi dengan baik untuk ukuran input kecil tetapi tidak berfungsi dengan baik ketika ukurannya bertambah   -  person Aznaveh    schedule 31.10.2020
comment
Anda harus mencari tahu apa keuntungan dari strategi ini seperti yang saya jelaskan sebelumnya. Saya akan menulis kelas pembungkus seputar hal ini yang melakukan optimasi jika menurutnya akan produktif, dan sebaliknya hanya melakukannya dengan cara default. Itu membuatnya lebih mudah untuk disetel.   -  person tadman    schedule 31.10.2020
comment
Mengapa Anda menginginkan indeks elemen set? Bahkan ketika Anda memilikinya, mengakses elemen (menggunakan std::distance() adalah O(n).   -  person Eugene    schedule 31.10.2020
comment
@Eugene itu adalah bagian dari proyek yang lebih besar. Saya akhirnya menyimpan set tersebut dalam array.   -  person Aznaveh    schedule 31.10.2020
comment
Tampaknya tidak masuk akal dalam proyek ukuran apa pun. Jika Anda bertanya tentang efisiensi, Anda juga perlu menjelaskan mengapa Anda memerlukan indeks. Perhatikan bahwa menemukan elemen dalam himpunan asli lebih cepat: yaitu O(log(n)), sedangkan dengan menggunakan indeks Anda adalah O(n).   -  person Eugene    schedule 31.10.2020
comment
@Eugene hash membuat O (panjang) menjadi O(1). Saya tidak mengerti dari mana O(n) itu berasal   -  person Aznaveh    schedule 31.10.2020
comment
Ya, mengakses peta tidak berurutan untuk mendapatkan indeks adalah O(1). Saya tidak bisa membayangkan situasi ketika memiliki indeks akan berguna untuk apa pun. Selama lebih dari 20 tahun pengalaman C++ saya, saya tidak pernah merasa perlu untuk mengambil indeks elemen set (menyimpan iterator bisa berguna). Jadi saya meminta untuk memberikan contoh bagaimana Anda akan menggunakan indeks, dan apa keuntungan kecepatan yang didapatnya.   -  person Eugene    schedule 31.10.2020
comment
O(n) berasal dari penggunaan std::distance(). Di mana lagi Anda akan menggunakan indeks?   -  person Eugene    schedule 31.10.2020
comment
Kecuali Anda memiliki hash yang sempurna, Anda tidak dijamin mendapatkan O(1), dan dalam kasus terburuk Anda mendapatkan O(N).   -  person Surt    schedule 31.10.2020
comment
Tidak jelas bagi saya apa nilai indeks dari setiap nilai dalam suatu set, dalam urutan iterasi. Tidak ada metode himpunan untuk mengembalikan nilai dengan indeks yang diberikan. Ini tampak seperti solusi untuk mencari masalah.   -  person Sam Varshavchik    schedule 31.10.2020
comment
@Eugene membuat pencarian indeks sangat masuk akal karena iterator akan menjadi tidak valid saat diubah ukurannya.   -  person ALX23z    schedule 31.10.2020
comment
@ALX23z std::set tidak valid saat diubah ukurannya, tidak ada pengubahan ukuran ...   -  person Surt    schedule 31.10.2020
comment
Masalahnya kemungkinan besar disebabkan oleh ukuran array. Membuat pencarian terlalu besar tentu menimbulkan masalah karena alokasi terfragmentasi yang terlalu besar. Pertimbangkan solusi algoritmik untuk proyek Anda. Cobalah mencari indeks dengan cara lain atau gunakan pmr untuk alokasi di unordered_map. Jika Anda hanya menambahkan elemen, mungkin Anda bisa membuat reservasi dalam jumlah besar dan meletakkan elemen satu demi satu   -  person ALX23z    schedule 31.10.2020
comment
@Surt ketika dia menulis SomeSet dia mengatakan bahwa dia menyimpan indeks dari sebuah array.   -  person ALX23z    schedule 31.10.2020


Jawaban (2)


Masalahnya adalah, std::unordered_map, terutama diimplementasikan sebagai daftar vektor, sangat tidak ramah terhadap cache, dan akan berkinerja sangat buruk dengan kunci/nilai kecil (seperti int,int dalam kasus Anda), belum lagi membutuhkan banyak alokasi (ulang).

Sebagai alternatif, Anda dapat mencoba peta hash pihak ketiga yang menerapkan pengalamatan terbuka dengan penyelidikan linier (sedikit, tetapi struktur dasarnya hanyalah sebuah vektor, sehingga lebih ramah terhadap cache). Misalnya, dense_hash_map Google atau ini: flat_hash_map. Keduanya dapat digunakan sebagai pengganti drop-in untuk unordered_map, dan hanya perlu menetapkan satu nilai int sebagai kunci kosong.

person rustyx    schedule 31.10.2020
comment
std::unordered_map tidak mempunyai masalah dengan realokasi. Mungkin tabel pencarian memerlukan elemen tersebut tetapi bukan elemen dasarnya. Itu memang menghasilkan banyak alokasi sehingga tidak disarankan untuk hash besar. - person ALX23z; 31.10.2020
comment
Saya akhirnya menerapkan hash saya sendiri menggunakan penyelidikan linier. Ini jauh lebih efisien. - person Aznaveh; 08.11.2020

std::unordered_map‹int, int› sering diimplementasikan seolah-olah memang demikian

std::vector<std::list<std::par<int, int>>> 

Yang menyebabkan banyak alokasi dan dealokasi setiap node, setiap (de-)alokasi menggunakan kunci yang menyebabkan pertikaian.

Anda dapat sedikit membantu dengan menggunakan emplace alih-alih menyisipkan, atau Anda dapat terjun ke dunia pengalokasi pmr baru yang fantastis. Jika pembuatan dan penghancuran pmr::unordered_map Anda adalah single threaded, Anda seharusnya bisa mendapatkan banyak kinerja ekstra darinya. Lihat Jason Turners C++ Weekly - Ep 222 - Kontainer Standar 3,5x Lebih Cepat Dengan PMR!, contohnya agak kecil tetapi Anda bisa mendapatkan gambaran umum.

person Surt    schedule 30.10.2020
comment
Deskripsi masalahnya benar, tapi saya tidak terlalu yakin PMR adalah rekomendasi terbaik. Tabel hash Google banyak digunakan, dan ada opsi lain yang lebih cepat - probablydance.com/2017/02/26/i-wrote-the-fastest-hashtable adalah bacaan yang bagus. - person Tony Delroy; 31.10.2020