Biasanya fungsi hash sederhana bekerja dengan mengambil "bagian komponen" dari input (karakter dalam kasus string), dan mengalikannya dengan kekuatan beberapa konstanta, dan menambahkannya bersama dalam beberapa tipe integer. Jadi misalnya hash khas (walaupun tidak terlalu bagus) dari string mungkin:
(first char) + k * (second char) + k^2 * (third char) + ...
Kemudian jika sekelompok string yang semuanya memiliki karakter pertama yang sama dimasukkan, maka hasilnya semua akan menjadi modulo k yang sama, setidaknya sampai tipe integer meluap.
[Sebagai contoh, kode Java string hash mirip dengan ini - ia melakukan urutan karakter terbalik, dengan k = 31. Jadi Anda mendapatkan hubungan yang mengejutkan modulo 31 antara string yang berakhir dengan cara yang sama, dan hubungan yang mengejutkan modulo 31 ^ antara string yang sama kecuali di dekat akhir. Ini tidak secara serius mengacaukan perilaku hashtable.]
Hash bekerja dengan mengambil modulus hash di atas jumlah bucket.
Sangat penting dalam hashtabel untuk tidak menghasilkan collision untuk kemungkinan kasus, karena collision mengurangi efisiensi hashtable.
Sekarang, anggaplah seseorang meletakkan sejumlah nilai ke dalam hashtable yang memiliki hubungan antara item-item tersebut, seperti semua yang memiliki karakter pertama yang sama. Ini adalah pola penggunaan yang cukup dapat diprediksi, saya katakan, jadi kami tidak ingin itu menghasilkan terlalu banyak tabrakan.
Ternyata "karena sifat matematika", jika konstanta yang digunakan dalam hash, dan jumlah ember, adalah koprime , maka tabrakan diminimalkan dalam beberapa kasus umum. Jika mereka bukan koprime, maka ada beberapa hubungan yang cukup sederhana antara input yang tabrakannya tidak diminimalkan. Semua hash keluar sama modulo faktor umum, yang berarti mereka semua akan jatuh ke 1 / n dari ember yang memiliki nilai modulo faktor umum. Anda mendapatkan n kali lebih banyak tabrakan, di mana n adalah faktor umum. Karena n setidaknya 2, saya akan mengatakan itu tidak dapat diterima untuk kasus penggunaan yang cukup sederhana untuk menghasilkan setidaknya dua kali lebih banyak tabrakan seperti biasa. Jika beberapa pengguna akan memecah distribusi kami menjadi ember, kami ingin itu menjadi kecelakaan aneh, bukan penggunaan yang dapat diprediksi sederhana.
Sekarang, implementasi hashtable jelas tidak memiliki kendali atas item yang dimasukkan ke dalamnya. Mereka tidak bisa mencegah mereka berhubungan. Jadi yang harus dilakukan adalah memastikan bahwa konstanta dan jumlah bucket adalah koprime. Dengan begitu Anda tidak mengandalkan komponen "terakhir" sendirian untuk menentukan modulus bucket sehubungan dengan beberapa faktor umum kecil. Sejauh yang saya tahu mereka tidak harus menjadi yang utama untuk mencapai ini, hanya coprime.
Tetapi jika fungsi hash dan hashtable ditulis secara independen, maka hashtable tidak tahu bagaimana fungsi hash bekerja. Mungkin menggunakan konstanta dengan faktor-faktor kecil. Jika Anda beruntung, itu mungkin bekerja dengan sangat berbeda dan tidak linier. Jika hash cukup baik, maka jumlah bucket apa pun baik-baik saja. Tetapi hashtable paranoid tidak dapat mengasumsikan fungsi hash yang baik, jadi sebaiknya gunakan jumlah bucket yang prima Demikian pula fungsi hash paranoid harus menggunakan konstanta prime yang lebih besar, untuk mengurangi kemungkinan seseorang menggunakan sejumlah ember yang kebetulan memiliki faktor umum dengan konstanta.
Dalam praktiknya, saya pikir cukup normal untuk menggunakan kekuatan 2 sebagai jumlah ember. Ini nyaman dan menghemat harus mencari sekitar atau pra-pilih nomor utama dari besaran yang tepat. Jadi, Anda mengandalkan fungsi hash untuk tidak menggunakan pengganda genap, yang umumnya merupakan asumsi yang aman. Tetapi Anda masih bisa mendapatkan perilaku hashing buruk sesekali berdasarkan fungsi hash seperti di atas, dan jumlah bucket prima dapat membantu lebih lanjut.
Menerapkan prinsip bahwa "semuanya harus prima" sejauh yang saya tahu cukup tetapi bukan syarat yang diperlukan untuk distribusi yang baik di atas tagar. Ini memungkinkan semua orang untuk beroperasi tanpa perlu berasumsi bahwa yang lain telah mengikuti aturan yang sama.
[Sunting: ada alasan lain yang lebih terspesialisasi untuk menggunakan jumlah bucket prima, yaitu jika Anda menangani tabrakan dengan probe linear. Lalu Anda menghitung langkah dari kode hash, dan jika langkah itu keluar menjadi faktor jumlah ember maka Anda hanya bisa melakukan (bucket_count / langkah) penyelidikan sebelum Anda kembali ke tempat Anda mulai. Kasus yang paling ingin Anda hindari adalah stride = 0, tentu saja, yang harus dikurung khusus, tetapi untuk menghindari juga casing-khusus bucket_count / stride sama dengan integer kecil, Anda bisa menjadikan bucket_count prima dan tidak peduli apa pun yang terjadi. langkahnya asalkan bukan 0.]