Tabel hash dikatakan diamortisasi menggunakan rantai sederhana dan dua kali lipat pada kapasitas tertentu.
Namun, ini mengasumsikan panjang elemen konstan. Menghitung hash suatu elemen membutuhkan melalui elemen, mengambil waktu di mana adalah panjangnya.
Tetapi untuk membedakan antara elemen, kita membutuhkan elemen yang memiliki panjang setidaknya bit; jika tidak dengan prinsip pigeonhole mereka tidak akan berbeda. Fungsi hash melalui bit elemen akan memakan waktu .
Jadi bisakah kita mengatakan bahwa kecepatan tabel hash, dengan mempertimbangkan fungsi hash yang masuk akal yang menggunakan semua bagian dari input, sebenarnya ? Lalu, mengapa tabel hash dalam praktiknya efisien untuk menyimpan elemen panjang variabel, seperti string dan integer besar?
sumber
Jawaban:
Kisah bahwa tabel hash diamortisasi adalahΘ(1)
kebohonganpenyederhanaan berlebihan.Ini hanya berlaku jika:k
c
r
- Jumlah data untuk hash per item sepele dibandingkan dengan jumlah K eys dan kecepatan hashing K ey cepat - . - Jumlah C ollisions kecil - . - Kami tidak memperhitungkan waktu akun yang dibutuhkan untuk R esize tabel hash - .
String besar untuk hashΘ(k)
Θ(k) O(1) Ω(k) O(k) Ω(k)
Jika asumsi pertama salah, waktu berjalan akan naik ke . Ini benar untuk string besar, tetapi untuk string besar perbandingan sederhana juga akan memiliki waktu berjalan . Jadi hash tidak lebih lambat secara asimptot, meskipun hashing akan selalu lebih lambat daripada perbandingan sederhana, karena perbandingan memiliki awal memilih keluar ergo , dan hashing selalu harus hash string penuh , .
Perhatikan bahwa bilangan bulat tumbuh sangat lambat. 8 byte dapat menyimpan nilai hingga ; 8 byte adalah jumlah yang sepele untuk hash. Jika Anda ingin menyimpan bigints maka anggap saja itu sebagai string.1018
Algoritma hash lambatΘ(1)
Jika hashing pengeluaran jumlah adalah non-sepele dibandingkan dengan penyimpanan data maka jelas asumsi menjadi tidak bisa dipertahankan. Kecuali jika hash kriptografi digunakan, ini seharusnya tidak menjadi masalah.
Yang penting . Selama itu berlaku adalah pernyataan yang adil.n >> k Θ(1)
Banyak tabrakanO(log(n))
Jika fungsi hashing buruk, atau tabel hash kecil, atau ukuran tabel hash canggung tabrakan akan sering dan waktu berjalan akan pergi ke . Fungsi hashing harus dipilih sehingga tabrakan jarang terjadi sementara masih secepat mungkin, ketika ragu-ragu memilih tabrakan yang lebih sedikit dengan mengorbankan hashing yang lebih lambat. Aturan praktisnya adalah bahwa tabel hashing harus selalu kurang dari 75% penuh. Dan ukuran tabel hashing seharusnya tidak memiliki korelasi dengan fungsi hashing. Seringkali ukuran tabel hashing (relatif) prima.
Mengubah ukuran tabel hash
Karena tabel hash yang hampir penuh akan memberikan terlalu banyak tabrakan dan tabel hash (kosong) yang besar adalah pemborosan ruang, banyak implementasi yang memungkinkan tabel hash untuk tumbuh (dan menyusut!) Sesuai kebutuhan.
Pertumbuhan tabel dapat melibatkan salinan lengkap semua item (dan mungkin perombakan), karena penyimpanan harus kontinu untuk alasan kinerja.
Hanya dalam kasus-kasus patologis perubahan ukuran tabel hash menjadi masalah sehingga ukuran (mahal tapi jarang) diamortisasi di banyak panggilan.
Running timeΘ(kcr)
k c r Θ(1)
Jadi waktu running sebenarnya dari tabel hash adalah . Setiap , , rata-rata diasumsikan sebagai konstanta (kecil) dalam waktu berjalan diamortisasi dan dengan demikian kita mengatakan bahwa adalah pernyataan yang adil.
Untuk kembali ke pertanyaan Anda.
Maafkan saya karena parafrase, saya sudah mencoba untuk mengekstrak berbagai makna, jangan ragu untuk berkomentar jika saya melewatkan beberapa
Anda tampaknya khawatir tentang panjang output dari fungsi hash. Sebut ini ( umumnya dianggap jumlah item yang akan di-hash). akan menjadi karena m perlu mengidentifikasi entri dalam tabel hash secara unik. Ini berarti bahwa m tumbuh sangat lambat. Pada 64 bit jumlah entri tabel hash akan mengambil porsi yang cukup besar dari RAM yang tersedia di seluruh dunia. Pada 128 bit itu akan jauh melebihi penyimpanan disk yang tersedia di planet bumi. Memproduksi hash 128 bit tidak jauh lebih sulit daripada hash 32 bit, jadi tidak , waktu untuk membuat hash bukanlah (atau jika Anda mau).m n m log(n)
O(m) O(log(n))
Tetapi fungsi hash tidak melalui bit elemen. Per satu item (!!) hanya berlaku untuk data . Juga panjang input (k) tidak ada hubungannya dengan jumlah elemen. Ini penting, karena beberapa algoritma non hashing harus memeriksa banyak elemen dalam koleksi untuk menemukan elemen (non) yang cocok. Tabel hash hanya melakukan perbandingan 1 atau 2 per item yang sedang dipertimbangkan rata-rata sebelum mencapai kesimpulan.log(n)
O(k)
Karena terlepas dari panjang input ( ) panjang output ( ) selalu sama, tabrakan jarang terjadi dan waktu pencarian konstan. Namun ketika panjang kunci tumbuh besar dibandingkan dengan jumlah item dalam tabel hash ( ) cerita berubah ...k m
k n
Tabel hash tidak terlalu efisien untuk string yang sangat besar.
Jika (yaitu ukuran input agak besar dibandingkan dengan jumlah item dalam tabel hash) maka kita tidak bisa lagi mengatakan bahwa hash memiliki waktu berjalan yang konstan, tetapi harus beralih ke waktu berjalan dari terutama karena tidak ada awal. Anda harus hash kunci lengkap. Jika Anda hanya menyimpan sejumlah item terbatas, maka Anda mungkin jauh lebih baik menggunakan penyimpanan yang diurutkan, karena ketika membandingkan Anda dapat memilih keluar segera setelah perbedaan terlihat.not n>>k Θ(k) k1 ≠ k2
Namun, jika Anda mengetahui data Anda, Anda dapat memilih untuk tidak meng-hash kunci penuh, tetapi hanya bagian (dikenal atau diasumsikan) yang volatil darinya, memulihkan properti sembari tetap menjaga tabrakan tetap terkendali.Θ(1)
Konstanta TersembunyiΘ(1)
Karena semua orang harus tahu berarti bahwa waktu per elemen yang diproses adalah konstan. Konstanta ini sedikit lebih besar untuk hashing daripada untuk perbandingan sederhana. Untuk tabel kecil, pencarian biner akan lebih cepat daripada pencarian hash, karena misalnya 10 perbandingan biner mungkin lebih cepat daripada hash tunggal. Untuk dataset kecil, alternatif untuk tabel hash harus dipertimbangkan. Ada pada dataset besar yang tabel hash benar-benar bersinar.
sumber
Mari kita mulai dengan pertanyaan yang lebih sederhana. Pertimbangkan apa yang mungkin merupakan struktur data paling sederhana yang ada, sebuah array . Untuk konkret, mari kita bayangkan sebuah array bilangan bulat. Berapa lama waktu yang dibutuhkan oleh operasi ? Jawabannya tergantung pada model perhitungan. Dua model relevan di sini: model RAM (yang lebih umum) dan model bit (yang lebih mudah dijelaskan).A[i]=A[j]
Dalam model yang sedikit , operasi dasar yang melibatkan bit biaya . Jadi jika bilangan bulat lebar bit, operasi akan menelan biaya sekitar .N N w A[i]=A[j] 2w
Dalam model RAM , unit dasar data tidak sedikit tetapi kata (kadang-kadang dikenal sebagai kata mesin ). Kata adalah bilangan bulat dengan lebar , di mana adalah ukuran input (dalam bit). Operasi dasar yang melibatkan kata biaya . Dalam kebanyakan kasus, jika Anda memiliki array bilangan bulat maka bilangan bulat yang Anda butuhkan memiliki lebar , sehingga operasi biaya .logn n N N O(logn) A[i]=A[j] O(1)
Seperti yang saya katakan di atas, kami biasanya menganalisis algoritma menggunakan model RAM. Satu-satunya pengecualian yang umum adalah bilangan bulat aritmatika, khususnya perkalian bilangan bulat, yang sering dianalisis sehubungan dengan jumlah operasi bit.
Mengapa kita menggunakan model RAM? Karena memiliki kekuatan yang lebih prediktif (vis a vis realitas). Asumsi bahwa ukuran input paling eksponensial dalam ukuran kata mesin biasanya dibenarkan, terutama untuk prosesor 64-bit modern, dan operasi pada kata-kata mesin memakan waktu konstan dalam CPU yang sebenarnya.
Tabel hash adalah struktur data yang lebih rumit, dan mereka benar-benar melibatkan tiga jenis: tipe kunci, tipe hash, dan tipe nilai. Dari sudut pandang tipe nilai , tabel hash hanyalah array yang dimuliakan, jadi mari kita abaikan aspek itu. The tipe hash selalu dapat diasumsikan terdiri dari sejumlah kecil kata mesin. The jenis kunci memenuhi properti khusus: itu adalah hashable , yang berarti bahwa ia memiliki operasi hash yang (minimal) adalah beberapa fungsi deterministik (fungsi selalu mengembalikan nilai yang sama).
Kami sekarang dapat menjawab pertanyaan Anda: berapa lama waktu yang dibutuhkan untuk memotong kunci? Jawabannya tergantung pada model perhitungan. Kali ini kami memiliki tiga model umum: dua model sebelumnya, dan model oracle.
Dalam model oracle , kita mengasumsikan bahwa fungsi hash diberikan kepada kita oleh "oracle" yang dapat menghitung hash dari kunci arbitrer dalam waktu yang konstan.
Dalam model RAM dan model bit , fungsi hash adalah fungsi yang sebenarnya, dan kompleksitas waktu dari tabel hash tergantung pada kompleksitas waktu dari fungsi hash. Fungsi hash yang digunakan untuk tabel hash (bukan untuk keperluan kriptografi) biasanya sangat cepat, dan membutuhkan waktu linier dalam input. Itu berarti bahwa jika tipe kunci memiliki panjang bit (dalam model bit) atau kata (dalam model RAM), fungsi hash membutuhkan waktu . Ketika adalah konstanta, fungsi hash membutuhkan waktu yang konstan.N N O(N) N
Ketika kami menganalisis waktu berjalan dari algoritma tabel hash, kami biasanya secara implisit menggunakan model oracle. Ini sering dinyatakan dalam bahasa yang berbeda: kami hanya mengatakan bahwa kami menghitung jumlah pemanggilan fungsi hash. Ini masuk akal, karena biasanya aplikasi fungsi hash adalah istilah dominan dalam waktu berjalan algoritma tabel hash, dan untuk menganalisis kompleksitas waktu aktual, yang harus Anda lakukan adalah mengalikan jumlah doa hash dengan waktu berjalan dari fungsi hash.
Ketika menganalisis waktu berjalan suatu algoritma menggunakan tabel hash sebagai struktur data, kita sering tertarik pada waktu berjalan yang sebenarnya, biasanya dalam model RAM. Salah satu opsi di sini adalah untuk melakukan apa yang disarankan dalam paragraf sebelumnya, yaitu untuk mengalikan waktu berjalan operasi tabel hash (diberikan dalam hal jumlah pemanggilan fungsi hash) dengan waktu berjalan fungsi hash.
Namun, ini tidak cukup baik jika tombol memiliki panjang yang bervariasi. Sebagai contoh, bayangkan kita memiliki kunci ukuran , dan kita menghitung hash masing-masing sekali. Kompleksitas waktu aktual adalah , tetapi perhitungan di atas hanya menghasilkan . Jika hal ini terjadi pada beberapa aplikasi, kita dapat memperhitungkannya secara ad hoc, menggunakan analisis yang disempurnakan dari kompleksitas tabel hash yang mendasarinya.1,2,4,…,2m O(2m) O(m2m)
sumber