(Kapan) adalah pencarian tabel hash O (1)?

71

Sering dikatakan bahwa pencarian tabel hash beroperasi dalam waktu konstan: Anda menghitung nilai hash, yang memberi Anda indeks untuk pencarian array. Namun ini mengabaikan tabrakan; dalam kasus terburuk, setiap item kebetulan mendarat di ember yang sama dan waktu pencarian menjadi linear ( ).Θ(n)

Apakah ada kondisi pada data yang dapat membuat pencarian tabel hash benar-benar ? Apakah itu hanya rata-rata, atau dapatkah tabel hash memiliki O (1) pencarian kasus terburuk?O ( 1 )HAI(1)HAI(1)

Catatan: Saya datang dari sudut pandang programmer di sini; ketika saya menyimpan data dalam tabel hash, itu hampir selalu string atau beberapa struktur data komposit, dan data berubah selama masa pakai tabel hash. Jadi, sementara saya menghargai jawaban tentang hash yang sempurna, mereka lucu tetapi anekdot dan tidak praktis dari sudut pandang saya.

PS Follow-up: Untuk jenis data apa operasi tabel hash O (1)?

Gilles 'SANGAT berhenti menjadi jahat'
sumber
3
Bisakah Anda hidup dengan waktu akses diamortisasi? Secara umum, kinerja tabel hash akan sangat tergantung pada berapa banyak overhead untuk hashtables jarang Anda siap untuk mentolerir dan pada bagaimana nilai hash yang sebenarnya didistribusikan. HAI(1)
Raphael
5
Oh, btw: Anda dapat menghindari perilaku linear terburuk dengan menggunakan pohon pencarian (seimbang) alih-alih daftar.
Raphael
1
@ Raphael Saya akan sangat tertarik dengan jawaban yang menjelaskan (sepanjang garis besar) ketika saya dapat mengandalkan diamortisasi dan ketika saya tidak bisa. Adapun bagaimana nilai hash didistribusikan, itu bagian dari pertanyaan saya benar-benar: bagaimana saya bisa tahu? Saya tahu fungsi hash seharusnya mendistribusikan nilai dengan baik; tetapi jika mereka selalu melakukan hal terburuk tidak akan pernah tercapai, itu tidak masuk akal. O(1)
Gilles 'SANGAT berhenti menjadi jahat'
1
Berhati-hatilah dengan pengoptimalan prematur; untuk data bertubuh kecil (beberapa ribu elemen) saya sering melihat pohon biner seimbang mengungguli hashtable karena overhead yang lebih rendah (perbandingan string jauh lebih murah daripada hash string). HAI(catatann)
isturdy

Jawaban:

41

Ada dua pengaturan di mana Anda bisa mendapatkan terburuk.HAI(1)

  1. Jika pengaturan Anda statis, maka hashing FKS akan memberi Anda jaminan terburuk . Tetapi seperti yang Anda tunjukkan, pengaturan Anda tidak statis.HAI(1)

  2. Jika Anda menggunakan hashing Cuckoo, maka kueri dan penghapusan adalah kasus terburuk, tetapi penyisipan hanya O ( 1 ) yang diharapkan. Cuckoo hashing bekerja cukup baik jika Anda memiliki batas atas jumlah sisipan, dan atur ukuran tabel menjadi sekitar 25% lebih besar.HAI(1)HAI(1)

Ada informasi lebih lanjut di sini .

Suresh
sumber
3
Bisakah Anda memperluas FKS dan Cuckoo? Kedua istilah itu baru bagi saya.
Gilles 'SO- stop being evil'
1
Bagaimana dengan hashing dinamis sempurna? Ini memiliki pencarian kasus terburuk dan O ( 1 ) penyisipan dan penghapusan diamortisasi. ( citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.30.8165 )HAI(1)HAI(1)
Joe
2
FKS adalah inisial dari (Fredman, Komlós, Szemerédi) dan Cuckoo adalah nama spesies pengantin. Ini digunakan untuk hashing jenis ini, karena ayam cuckoo mendorong telur saudara dari sarang. Ini agak mirip bagaimana fungsi metode hasing ini.
uli
1
@ Suresh: Benarkah? Saya pikir Anda perlu fungsi independen, yang saya selalu dikaitkan dengan membutuhkan ekspander. Saya berdiri dikoreksi. Akan sedikit komentar saya dihapus. catatann
Louis
1
Untuk membuat komentar yang lebih berguna pada jawaban ini, seperti yang ditunjukkan oleh @Suresh, hashing cuckoo akan bekerja dengan baik tanpa fungsi hash mewah (dan besar) yang digunakan untuk menganalisisnya secara teoritis.
Louis
21

Jawaban ini merangkum bagian-bagian dari TAoCP Vol 3, Bab 6.4.

Asumsikan kita memiliki seperangkat nilai , n yang ingin kita simpan dalam array A ukuran m . Kami menggunakan fungsi hash h : V [ 0 .. M ) ; biasanya, M | V | . Kami memanggil α = nVnSEBUAHmh:V[0 ..M.)M.|V| denganload factordariA. Di sini, kita akan mengasumsikan naturalm=M; dalam skenario praktis, kita memilikim«M, meskipun, dan harus memetakan kemdiri kita sendiri.α=nmSEBUAHm=M.mM.m

Pengamatan pertama adalah bahwa bahkan jika memiliki karakteristik seragam-probabilitas dua nilai memiliki nilai hash yang sama tinggi; ini pada dasarnya adalah contoh dari paradoks ulang tahun yang terkenal . Oleh karena itu, kita biasanya harus berurusan dengan konflik dan dapat meninggalkan harapan O ( 1 ) waktu akses kasus terburuk.hHAI(1)

Bagaimana dengan kasus rata-rata? Mari kita asumsikan bahwa setiap kunci dari muncul dengan probabilitas yang sama. Jumlah rata-rata entri yang diperiksa C S n (pencarian berhasil) resp. C U n (pencarian yang gagal) tergantung pada metode resolusi konflik yang digunakan.[0 ..M.)CnSCnU

Rantai

Setiap entri array berisi (pointer ke kepala) daftar tertaut. Ini adalah ide yang bagus karena panjang daftar yang diharapkan kecil ( ) meskipun probabilitas untuk tabrakan tinggi. Pada akhirnya, kita mendapatkan C S n1+αnm Ini dapat ditingkatkan sedikit dengan menyimpan daftar (sebagian atau seluruhnya) di dalam tabel.

CnS1+α2 dan CnU1+α22.

Probing Linier

Ketika memasukkan (resp. Mencari nilai) , periksa posisi h ( v ) , h ( v ) - 1 , , 0 , m - 1 , , h ( v ) + 1 dalam urutan ini hingga posisi kosong (resp . v ) ditemukan. Keuntungannya adalah kami bekerja secara lokal dan tanpa struktur data sekunder; Namun, jumlah akses rata-rata berbeda untuk α 1 : C S n1v

h(v),h(v)-1,...,0,m-1,...,h(v)+1
vα1 Namun untukα<0,75, kinerjanya sebanding dengan chaining².
CnS12(1+11-α) dan CnU12(1+(11-α)2).
α<0,75

Hashing ganda

Mirip dengan linear probing tetapi ukuran langkah pencarian dikendalikan oleh fungsi hash kedua yang coprime untuk . Tidak ada derivasi formal yang diberikan, tetapi pengamatan empiris menunjukkan C S n1M. Metode ini telah diadaptasi oleh Brent; variannya diamortisasi meningkatkan biaya penyisipan dengan pencarian lebih murah.

CnS1αdalam(11-α) dan CnU11-α.

Perhatikan bahwa menghapus elemen dari dan memperluas tabel memiliki berbagai tingkat kesulitan untuk metode masing-masing.

Intinya, Anda harus memilih implementasi yang beradaptasi dengan baik dengan kasus penggunaan khas Anda. Waktu akses yang diharapkan dalam dimungkinkan jika tidak selalu dijamin. Tergantung pada metode yang digunakan, menjaga α rendah sangat penting; Anda harus menukar waktu akses (yang diharapkan) dengan overhead ruang. Pilihan yang baik untuk h juga sangat penting.HAI(1)αh


h
Hashtable

Raphael
sumber
10

S{0,1,2,...,n}HAI(1)HAI(1)lSlxxSHAI(|l|)SHAI(|S|)HAI(|l|+|S|)HAI(|l||S|)O(log(|l|)|S|)O(|l|)l

O(|l|)

lUNSUxSllh:U{trkamue,fSebuahlse}hh(x)=fSebuahlsexUylh(y)=trkamueHAI(|l|)HAI(|U|)

lHAI(|U|)HAI(|1|)HAI(|U|)

Uh

Patrick87
sumber
HAI(|l|)HAI(|S|)HAI(|l||S|)
hh:U{fSebuahlse,trkamue}h
@Gilles Ini pada dasarnya hanya digunakan sebagai tabel pencarian untuk keanggotaan daftar. Ketika Anda memiliki fungsi hash sempurna dengan invers yang dikenal & murah, alih-alih menyimpannya sendiri, Anda hanya perlu menyimpan 1 bit (apakah benda dengan hash unik telah ditambahkan). Jika tabrakan mungkin terjadi, saya pikir melakukan ini disebut sebagai filter Bloom, tetapi dalam hal apa pun dapat memberikan "tidak" yang pasti untuk masalah keanggotaan, yang masih berguna dalam banyak skenario.
Patrick87
9

HAI(1)

HAI(1)HAI(1)HAI(1)HAI(1)

Nicholas Meyer
sumber
Fungsi hash yang sempurna akan sempurna, tetapi bagaimana cara mendapatkannya? Berapa biayanya bagi saya? Dan bagaimana saya tahu berapa jumlah tumbukan maksimum atau yang diharapkan?
Gilles 'SANGAT berhenti menjadi jahat'
2
@Gilles fungsi hash sempurna adalah fungsi apa pun yang akan menghasilkan hash unik untuk semua input yang mungkin. Jika kemungkinan input Anda terbatas (dan unik), ini mudah dilakukan.
Rafe Kettler
1
@RafeKettler Input saya biasanya berupa string atau struktur data majemuk, dan saya biasanya menambah dan menghapus entri saat data saya berkembang. Bagaimana cara membuat hash yang sempurna untuk ini?
Gilles 'SO- stop being evil'
4
Ya, tapi itu intinya. Fungsi hash sempurna deterministik tidak ada jika domain lebih besar dari rentang.
Suresh
@ Suresh: Jika Anda diizinkan untuk memilih fungsi hash baru dan meningkatkan ukuran tabel setiap kali terjadi tabrakan, Anda selalu dapat menemukan fungsi hash (deterministik) yang - untuk data yang sudah ada di tabel plus yang baru item yang Anda coba masukkan - tidak memiliki tabrakan ("sempurna"). Itulah sebabnya hashing dinamis sempurna secara berkala memilih fungsi hash baru acak.
David Cary