Saya mencari implementasi tipe data yang ditetapkan. Kita harus melakukannya
- memelihara subset dinamis (ukuran ) dari alam semesta dari ukuran dengan
- operasi
insert(x)
(tambahkan elemenx
ke ) dan (memeriksa apakah elemen adalah anggota ).find(x)
x
Saya tidak peduli dengan operasi lain. Untuk orientasi, dalam aplikasi yang saya gunakan, kami memiliki .
Saya tahu implementasi yang menyediakan kedua operasi dalam waktu , jadi saya khawatir sebagian besar tentang ukuran struktur data. Saya mengharapkan milyaran entri tetapi ingin menghindari pertukaran sebanyak mungkin.
Saya bersedia mengorbankan runtime jika perlu. Runtime diamortisasi dari adalah apa yang dapat saya akui; runtime yang diharapkan atau runtime di tidak dapat diterima.
Satu ide yang saya miliki adalah bahwa jika dapat direpresentasikan sebagai gabungan rentang , maka kita akan dapat menghemat ukuran penyimpanan dengan harga beberapa penurunan kinerja. Juga, beberapa pola data lain dimungkinkan, seperti .[xmin, xmax]
[0, 2, 4, 6]
Bisakah Anda mengarahkan saya ke struktur data yang dapat melakukan sesuatu seperti itu?
n
adalah ukuran dari himpunan S. Hal ini dapat meningkat dengan setiapinsert
, atau dapat tetap sama jika elemenx
sudah ada di dalam himpunan.Jawaban:
Jawaban Joe sangat bagus, dan memberi Anda semua kata kunci penting.
Anda harus menyadari bahwa penelitian struktur data yang ringkas masih dalam tahap awal, dan banyak hasilnya sebagian besar bersifat teoritis. Banyak struktur data yang diusulkan cukup rumit untuk diimplementasikan, tetapi sebagian besar kerumitan disebabkan oleh fakta bahwa Anda perlu mempertahankan kompleksitas asimptotik baik di atas ukuran semesta dan jumlah elemen yang disimpan. Jika salah satu dari ini relatif konstan, maka banyak kerumitan hilang.
Jika koleksi semi-statis (yaitu, insert jarang, atau setidaknya volume rendah), maka tentu layak mempertimbangkan struktur data statis yang mudah diimplementasikan (Sadakane sdarray adalah pilihan yang baik) bersamaan dengan pembaruan cache. Pada dasarnya, Anda merekam pembaruan dalam struktur data tradisional (misalnya B-tree, trie, tabel hash), dan secara berkala memperbarui struktur data "utama". Ini adalah teknik yang sangat populer dalam pencarian informasi, karena indeks terbalik memiliki banyak keuntungan untuk pencarian tetapi sulit untuk memperbarui di tempat. Jika ini masalahnya, beri tahu saya dalam komentar dan saya akan mengubah jawaban ini untuk memberi Anda beberapa petunjuk.
Jika memasukkan lebih sering, maka saya sarankan hashing ringkas. Ide dasarnya cukup jelas untuk dijelaskan di sini, jadi saya akan melakukannya.
Jadi, hasil teoretik informasi dasar adalah bahwa jika Anda menyimpan elemen dari semesta item u , dan tidak ada informasi lain (misalnya tidak ada korelasi antara elemen) maka Anda memerlukan bit untuk menyimpannya. (Semua logaritma adalah basis-2 kecuali ditentukan lain.) Anda memerlukan banyak bit ini. Tidak ada jalan lain.n u log(un)+O(1)
Sekarang beberapa terminologi:
Perbedaan antara ringkas dan kompak adalah perbedaan antara oh kecil dan oh besar. Mengabaikan nilai absolut sesaat ...
Secara informal, besar-oh dan kecil-oh keduanya "dalam faktor konstan", tetapi dengan besar-oh konstanta dipilih untuk Anda (oleh perancang algoritma, produsen CPU, hukum fisika atau apa pun), tetapi dengan sedikit -oh Anda memilih konstanta sendiri dan itu bisa sekecil yang Anda suka . Dengan kata lain, dengan struktur data yang ringkas, overhead relatif menjadi sewenang-wenang kecil ketika ukuran masalah meningkat.
Tentu saja, ukuran masalah mungkin harus menjadi besar untuk mewujudkan overhead relatif yang Anda inginkan, tetapi Anda tidak dapat memiliki semuanya.
OK, dengan itu di bawah ikat pinggang kita, mari kita taruh beberapa nomor pada masalahnya. Misalkan kunci adalah bilangan bulat bit (jadi ukuran semesta adalah ), dan kami ingin menyimpan bilangan bulat ini. Misalkan kita dapat secara ajaib mengatur tabel hash ideal dengan hunian penuh dan tanpa pemborosan, sehingga kita membutuhkan slot hash tepat .2 n 2 m 2 mn 2n 2m 2m
Operasi pencarian akan hash tombol bit, tutup bit untuk menemukan slot hash, dan kemudian periksa untuk melihat apakah nilai dalam tabel cocok dengan kunci. Sejauh ini bagus.n m
Tabel hash seperti itu menggunakan bit. Bisakah kita berbuat lebih baik dari ini?n2m
Misalkan fungsi hash tidak dapat dibalik. Maka kita tidak perlu menyimpan seluruh kunci di setiap slot hash. Lokasi slot hash memberi Anda bit nilai hash, jadi jika Anda hanya menyimpan bit n - m yang tersisa, Anda dapat merekonstruksi kunci dari dua informasi tersebut (lokasi slot hash dan nilai yang disimpan di sana). Jadi Anda hanya perlu ( n - m ) 2 m bit penyimpanan.h m n−m (n−m)2m
Jika kecil dibandingkan dengan 2 n , perkiraan Stirling dan sedikit aritmatika (bukti adalah latihan!) Mengungkapkan bahwa:2m 2n
Jadi struktur data ini ringkas.
Namun, ada dua tangkapan.
Tangkapan pertama adalah membangun fungsi hash "baik" yang dapat dibalik. Untungnya, ini jauh lebih mudah daripada yang terlihat; cryptographers membuat fungsi yang tidak dapat dibalik sepanjang waktu, hanya mereka menyebutnya "cyphers". Anda bisa, misalnya, mendasarkan fungsi hash pada jaringan Feistel, yang merupakan cara mudah untuk membangun fungsi hash yang tidak dapat dibalik dari fungsi hash yang tidak dapat dibalik.
Tangkapan kedua adalah bahwa tabel hash nyata tidak ideal, berkat paradoks Ulang Tahun. Jadi, Anda ingin menggunakan jenis tabel hash yang lebih canggih yang membuat Anda lebih dekat ke hunian penuh tanpa tumpah. Cuckoo hashing sangat cocok untuk ini, karena memungkinkan Anda untuk mendekati ideal secara teori, dan cukup dekat dalam praktik.
Cuckoo hashing memang membutuhkan banyak fungsi hash, dan itu mengharuskan nilai-nilai dalam slot hash ditandai dengan fungsi hash yang digunakan. Jadi, jika Anda menggunakan empat fungsi hash, misalnya, Anda perlu menyimpan dua bit tambahan di setiap slot hash. Ini masih singkat sebagai tumbuh, sehingga tidak masalah dalam praktek, dan masih berdetak menyimpan seluruh kunci.m
Oh, Anda mungkin juga ingin melihat pohon van Emde Boas.
LEBIH BANYAK PIKIRAN
Jika ada di sekitar Andan , lalulogin ( uu2 kira-kirau, jadi (sekali lagi) dengan asumsi bahwa tidak ada korelasi lebih lanjut antara nilai-nilai, Anda pada dasarnya tidak dapat melakukan lebih baik daripada sedikit vektor. Anda akan mencatat bahwa solusi hashing di atas tidak secara efektif merosot ke kasing (Anda akhirnya menyimpan satu bit per slot hash), tetapi lebih murah hanya menggunakan kunci sebagai alamat daripada menggunakan fungsi hash.log(un) u
Jika sangat dekat dengan Anda , semua literatur struktur data yang ringkas menyarankan Anda untuk membalikkan arti kamus. Simpan nilai-nilai yang tidak terjadi di set. Namun, sekarang Anda secara efektif harus mendukung operasi penghapusan, dan untuk menjaga perilaku ringkas Anda juga harus dapat mengecilkan struktur data karena lebih banyak elemen yang "ditambahkan". Memperluas tabel hash adalah operasi yang dipahami dengan baik, tetapi mengontraknya tidak.n u
sumber
insert
akan disertai dengan panggilanfind
dengan argumen yang sama. Jadi, jikafind
kembalitrue
, maka kita lewati sajainsert
. Jadi, frekuensifind
panggilan lebih dari frekuensiinsert
panggilan, juga ketikan
menjadi dekatu
, makainsert
panggilan menjadi sangat jarang.n <= u
Sepertinya Anda menginginkan struktur data yang ringkas untuk masalah keanggotaan dinamis .
Ingatlah bahwa struktur data ringkas adalah struktur yang persyaratan ruangnya "dekat" dengan batas informasi-teoretis, tetapi tidak seperti struktur data terkompresi, masih memungkinkan permintaan yang efisien.
Masalah keanggotaan persis seperti yang Anda gambarkan dalam pertanyaan Anda:
find(x)
x
insert(x)
x
delete(x)
x
Jika hanya
find
operasi yang didukung, maka ini adalah masalah keanggotaan statis . Jika salah satuinsert
ataudelete
didukung, tetapi tidak keduanya, itu disebut semi-dinamis , dan jika ketiga operasi didukung, maka itu disebut masalah keanggotaan dinamis .Secara teknis, saya pikir Anda hanya meminta struktur data untuk masalah keanggotaan semi-dinamis, tetapi saya tidak tahu ada struktur data yang memanfaatkan kendala ini dan juga memenuhi persyaratan lainnya. Namun, saya memiliki referensi berikut:
Dalam Teorema 5.1 dari artikel Keanggotaan dalam Waktu Konstan dan Ruang Hampir Minimal , Brodnik dan Munro memberikan hasil sebagai berikut:
Ide dasarnya adalah bahwa mereka secara rekursif membagi alam semesta menjadi rentang ukuran yang dipilih dengan cermat, sehingga ini bahkan terdengar seperti teknik yang mungkin sepanjang garis yang Anda pikirkan.
sumber
n = u/2
, maka ruang yang dibutuhkan maksimal.