Mencari implementasi yang ditetapkan dengan jejak memori kecil

9

Saya mencari implementasi tipe data yang ditetapkan. Kita harus melakukannya

  • memelihara subset dinamis S (ukuran n ) dari alam semesta dari ukuran denganU={0,1,2,3,,u1}u
  • operasi insert(x)(tambahkan elemen xke ) dan (memeriksa apakah elemen adalah anggota ).Sfind(x)xS

Saya tidak peduli dengan operasi lain. Untuk orientasi, dalam aplikasi yang saya gunakan, kami memiliki .u1010

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.O(1)

Saya bersedia mengorbankan runtime jika perlu. Runtime diamortisasi dari adalah apa yang dapat saya akui; runtime yang diharapkan atau runtime di tidak dapat diterima.O(logn)ω(logn)

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 .S[xmin, xmax][0, 2, 4, 6]

Bisakah Anda mengarahkan saya ke struktur data yang dapat melakukan sesuatu seperti itu?

HEKTO
sumber
Bagaimana jumlah elemen masuk ke dalam gambar? Yaitu, apa yang terjadi jika suatu elemen dimasukkan dan sudah ada ? nn
vonbrand
@vonbrand - nadalah ukuran dari himpunan S. Hal ini dapat meningkat dengan setiap insert, atau dapat tetap sama jika elemen xsudah ada di dalam himpunan.
HEKTO
3
Bisakah Anda menerima sedikit kemungkinan positif palsu? Jika demikian, filter mekar mungkin ideal: en.wikipedia.org/wiki/Bloom_filter
Joe
1
@AlexeyYakovlev, tingkat positif palsu dari filter bloom tidak ada hubungannya dengan ukuran alam semesta (hanya dengan jumlah fungsi hash , ukuran struktur data , dan jumlah item ), tetapi jika benar-benar dekat dengan (katakanlah untuk konstanta kecil ), Anda akan kesulitan untuk melakukan lebih baik daripada vektor bit sederhana saya pikir, dengan hanya total bit ruang. kmnn u = n c c c nuu=ncccn
Joe

Jawaban:

8

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.nulog(un)+O(1)

Sekarang beberapa terminologi:

  • Jika Anda memiliki struktur data yang dapat menyimpan data dan mendukung operasi Anda di bit ruang, kami menyebutnya struktur data implisit .log(un)+O(1)
  • Jika Anda memiliki struktur data yang dapat menyimpan data dan mendukung operasi Anda di bit ruang, kami menyebutnya struktur data yang ringkas . Perhatikan bahwa dalam praktiknya ini berarti bahwa overhead relatif (relatif terhadap minimum teoritis) berada dalam konstanta. Itu bisa 5% overhead, atau 10% overhead, atau 10 kali overhead.log(un)+O(log(un))=(1+O(1))log(un)
  • Jika Anda memiliki struktur data yang dapat menyimpan data dan mendukung operasi Anda di bit ruang, kami menyebutnya struktur data yang ringkas .log(un)+o(log(un))=(1+o(1))log(un)

Perbedaan antara ringkas dan kompak adalah perbedaan antara oh kecil dan oh besar. Mengabaikan nilai absolut sesaat ...

  • c n 0 n > n 0 g ( n ) < c f ( n )g(n)=O(f(n)) berarti ada konstan dan angka sehingga untuk semua , .cn0n>n0g(n)<cf(n)
  • c n 0 n > n 0 g ( n ) < c f ( n )g(n)=o(f(n)) berarti bahwa untuk semua konstanta terdapat angka sehingga untuk semua , .cn0n>n0g(n)<cf(n)

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 mn2n2m2m

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.nm

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.hmnm(nm)2m

Jika kecil dibandingkan dengan 2 n , perkiraan Stirling dan sedikit aritmatika (bukti adalah latihan!) Mengungkapkan bahwa:2m2n

(nm)2m=log(2n2m)+o(log(2n2m))

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.nu

Nama samaran
sumber
Hai, seperti untuk paragraf kedua dari jawaban Anda - Saya berharap bahwa setiap panggilan insertakan disertai dengan panggilan finddengan argumen yang sama. Jadi, jika findkembali true, maka kita lewati saja insert. Jadi, frekuensi findpanggilan lebih dari frekuensi insertpanggilan, juga ketika nmenjadi dekat u, maka insertpanggilan menjadi sangat jarang.
HEKTO
Tapi kamu berharap akan mendekati n pada akhirnya? un
Nama samaran
Di dunia nyata n tumbuh hingga mencapai Anda, namun kita tidak dapat memprediksi apakah itu akan terjadi atau tidak. Struktur data harus bekerja dengan baik untuk apa sajan <= u
HEKTO
Baik. Kemudian itu adil untuk mengatakan bahwa kita tidak tahu dari struktur data tunggal yang singkat (dalam arti di atas) dan yang mencapai ini seluruh rentang . Saya pikir Anda akan menginginkan struktur data yang jarang ketikan<u, kemudian beralih ke yang padat (misalnya vektor sedikit) ketikanada di sekitarAndanun<un , maka struktur data yang jarang dengan indra terbalik ketikandekat denganu. u2nu
Nama samaran
5

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:

SnU={0,1,2,3,,u1}u

  • find(x)xS
  • insert(x)xS
  • delete(x)xS

Jika hanya findoperasi yang didukung, maka ini adalah masalah keanggotaan statis . Jika salah satu insertatau deletedidukung, 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:

O(B)

B=log(un)

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.

un

Joe
sumber
1
Abstrak makalah Brodnik & Munro tidak mengatakan apa-apa tentang sisipan. Tetapi hasilnya adalah apa yang bisa kita harapkan, kan? Jika n = u/2, maka ruang yang dibutuhkan maksimal.
HEKTO
@AlekseyYakovlev Mereka tidak benar-benar menyebutkan kasus dinamis dalam abstrak, tetapi teorema yang berkaitan dengan kasus dinamis dikutip dalam jawaban saya (dari bagian 5).
Joe