Jelas bahwa kinerja pencarian HashSet<T>
kelas generik lebih tinggi daripada List<T>
kelas generik . Bandingkan saja kunci berbasis hash dengan pendekatan linier di List<T>
kelas.
Namun menghitung kunci hash itu sendiri mungkin memerlukan beberapa siklus CPU, jadi untuk sejumlah kecil item pencarian linier dapat menjadi alternatif nyata untuk HashSet<T>
.
Pertanyaan saya: di mana impas?
Untuk menyederhanakan skenario (dan bersikap adil) mari kita asumsikan bahwa List<T>
kelas menggunakan metode elemen Equals()
untuk mengidentifikasi item.
.net
performance
collections
list
hash
Michael Damatov
sumber
sumber
Jawaban:
Banyak orang mengatakan bahwa setelah Anda mencapai ukuran di mana kecepatan sebenarnya merupakan masalah yang
HashSet<T>
akan selalu mengalahkanList<T>
, tetapi itu tergantung pada apa yang Anda lakukan.Katakanlah Anda memiliki
List<T>
yang hanya akan memiliki rata-rata 5 item di dalamnya. Lebih dari sejumlah besar siklus, jika satu item ditambahkan atau dihapus setiap siklus, Anda mungkin lebih baik menggunakan aList<T>
.Saya melakukan tes untuk ini pada mesin saya, dan, yah, itu harus sangat sangat kecil untuk mendapatkan keuntungan darinya
List<T>
. Untuk daftar string pendek, keuntungan hilang setelah ukuran 5, untuk objek setelah ukuran 20.Berikut adalah data yang ditampilkan sebagai grafik:
Berikut kodenya:
sumber
List<T>
mesin permainan, dan karena saya biasanya akan memiliki volume objek yang tinggi, koleksi semacam ini akan menjadi sempurna.Anda melihat ini salah. Ya, pencarian linear dari suatu Daftar akan mengalahkan HashSet untuk sejumlah kecil item. Namun perbedaan kinerja biasanya tidak masalah untuk koleksi sekecil itu. Ini umumnya koleksi besar yang harus Anda khawatirkan, dan di situlah Anda berpikir tentang Big-O . Namun, jika Anda telah mengukur hambatan nyata pada kinerja HashSet, maka Anda dapat mencoba membuat Daftar hybrid / HashSet, tetapi Anda akan melakukannya dengan melakukan banyak tes kinerja empiris - tidak mengajukan pertanyaan pada SO.
sumber
when small collection becomes large enough to worry about HashSet vs List?
puluhan, puluhan ribu, miliaran elemen?HashSet<T>
. Dalam kasus-kasus kecil di manaList<T>
mungkin lebih cepat, perbedaannya tidak signifikan . "Tidak ada gunanya membandingkan dua struktur untuk kinerja yang berperilaku berbeda. Gunakan struktur yang menyampaikan maksud. Bahkan jika Anda mengatakan Anda
List<T>
tidak akan memiliki duplikat dan urutan iterasi tidak masalah membuatnya sebanding dengan aHashSet<T>
, itu masih pilihan yang buruk untuk digunakanList<T>
karena relatif lebih toleran terhadap kesalahan.Yang mengatakan, saya akan memeriksa beberapa aspek kinerja lainnya,
Meskipun penambahan adalah O (1) dalam kedua kasus, itu akan relatif lebih lambat di HashSet karena melibatkan biaya precomputing kode hash sebelum menyimpannya.
Skalabilitas HashSet yang unggul memiliki biaya memori. Setiap entri disimpan sebagai objek baru bersama dengan kode hash-nya. Artikel ini mungkin memberi Anda ide.
sumber
Apakah menggunakan HashSet <> atau Daftar <> adalah bagaimana Anda perlu mengakses koleksi Anda . Jika Anda perlu menjamin urutan barang, gunakan Daftar. Jika tidak, gunakan HashSet. Biarkan Microsoft khawatir tentang penerapan algoritme dan objek hashing mereka.
HashSet akan mengakses item tanpa harus menyebutkan koleksi (kompleksitas O (1) atau di dekatnya), dan karena Daftar menjamin pesanan, tidak seperti HashSet, beberapa item harus disebutkan (kompleksitas O (n)).
sumber
List
lebih disukai, karena Anda dapat mengingat indeks - itu adalah situasi yang Anda sedang menggambarkan.Hanya berpikir saya akan berpadu dengan beberapa tolok ukur untuk skenario yang berbeda untuk menggambarkan jawaban sebelumnya:
Dan untuk setiap skenario, cari nilai yang muncul:
Sebelum setiap skenario saya membuat daftar string acak berukuran acak, dan kemudian memasukkan setiap daftar ke hashset. Setiap skenario berjalan 10.000 kali, pada dasarnya:
(test kodesemu)
Output Sampel
Diuji pada Windows 7, Ram 12GB, 64 bit, Xeon 2.8GHz
sumber
List
masih hanya membutuhkan 0,17 milidetik untuk melakukan pencarian tunggal, dan tidak akan membutuhkan penggantian untukHashSet
sampai frekuensi pencarian mencapai tingkat yang tidak masuk akal. Pada saat itu, penggunaan Daftar biasanya merupakan masalah yang paling kecil.Titik impas akan tergantung pada biaya komputasi hash. Perhitungan hash bisa sepele, atau tidak ... :-) Selalu ada kelas System.Collections.Specialized.HybridDictionary untuk membantu Anda tidak perlu khawatir tentang titik impas.
sumber
Jawabannya, seperti biasa, adalah " Itu tergantung ". Saya berasumsi dari tag yang Anda bicarakan tentang C #.
Taruhan terbaik Anda adalah menentukan
dan menulis beberapa test case.
Ini juga tergantung pada bagaimana Anda mengurutkan daftar (jika itu diurutkan sama sekali), perbandingan apa yang perlu dibuat, berapa lama operasi "Bandingkan" untuk objek tertentu dalam daftar, atau bahkan bagaimana Anda bermaksud menggunakan koleksi.
Secara umum, yang terbaik untuk dipilih bukan berdasarkan ukuran data yang Anda gunakan, tetapi bagaimana Anda akan mengaksesnya. Apakah Anda memiliki setiap bagian data yang terkait dengan string tertentu, atau data lainnya? Koleksi berbasis hash mungkin akan menjadi yang terbaik. Apakah urutan data yang Anda simpan penting, atau Anda perlu mengakses semua data pada saat yang sama? Daftar reguler mungkin lebih baik.
Tambahan:
Tentu saja, komentar saya di atas menganggap 'kinerja' berarti akses data. Sesuatu yang perlu dipertimbangkan: apa yang Anda cari ketika Anda mengatakan "kinerja"? Apakah nilai kinerja individu terlihat? Apakah manajemen set nilai besar (10000, 100000 atau lebih)? Apakah kinerja mengisi struktur data dengan data? Menghapus data? Mengakses bit data individual? Mengganti nilai? Iterasi atas nilai-nilai? Penggunaan memori? Kecepatan penyalinan data? Misalnya, Jika Anda mengakses data dengan nilai string, tetapi persyaratan kinerja utama Anda adalah penggunaan memori yang minimal, Anda mungkin memiliki masalah desain yang saling bertentangan.
sumber
Anda dapat menggunakan HybridDictionary yang secara otomatis mendeteksi titik putusnya, dan menerima nilai nol, menjadikannya sama pentingnya dengan HashSet.
sumber
Tergantung. Jika jawaban yang tepat benar-benar penting, lakukan beberapa profiling dan cari tahu. Jika Anda yakin tidak akan pernah memiliki lebih dari sejumlah elemen dalam set, buka Daftar. Jika nomornya tidak terikat, gunakan HashSet.
sumber
Tergantung pada apa yang Anda hashing. Jika kunci Anda bilangan bulat, Anda mungkin tidak perlu banyak item sebelum HashSet lebih cepat. Jika Anda mengetikkannya pada string maka itu akan lebih lambat, dan tergantung pada string input.
Tentunya Anda bisa menyiapkan tolok ukur dengan cukup mudah?
sumber
Salah satu faktor yang tidak Anda perhitungkan adalah kekokohan fungsi GetHashcode (). Dengan fungsi hash yang sempurna, HashSet jelas akan memiliki kinerja pencarian yang lebih baik. Tetapi karena fungsi hash berkurang, maka waktu pencarian HashSet juga akan berkurang.
sumber
Tergantung pada banyak faktor ... Implementasi daftar, arsitektur CPU, JVM, loop semantik, kompleksitas metode yang sama, dll ... Pada saat daftar menjadi cukup besar untuk secara efektif melakukan benchmark (1000+ elemen), biner berbasis hash pencarian mengalahkan pencarian linier tangan-down, dan perbedaannya hanya naik dari sana.
Semoga ini membantu!
sumber