Inisialisasi array dalam waktu konstan diamortisasi - apa trik ini disebut?

13

Ada struktur data ini yang memperdagangkan kinerja akses array terhadap kebutuhan untuk mengulanginya saat membersihkannya. Anda menyimpan penghitung generasi dengan setiap entri, dan juga penghitung generasi global. Operasi "jelas" meningkatkan penghitung generasi. Pada setiap akses, Anda membandingkan penghitung generasi lokal vs global; jika berbeda, nilainya diperlakukan sebagai "bersih".

Ini muncul dalam jawaban di Stack Overflow baru-baru ini, tapi saya tidak ingat apakah trik ini memiliki nama resmi. Melakukannya?

Salah satu use case adalah algoritma Dijkstra jika hanya sebagian kecil dari node harus santai, dan jika ini harus dilakukan berulang kali.

krlmlr
sumber
2
Trik yang menarik, tetapi memiliki overhead yang cukup. Jadi saya bertanya-tanya penggunaan mana yang telah menghapus array seperti operasi umum yang dibayar oleh harga? (Pertanyaan yang tulus!)
Joachim Sauer
@ JoachimSauer: Diedit.
krlmlr
Kedengarannya sangat mahal pada kasus umum untuk penggunaan memori dan biaya akses. Kasus penggunaan untuk teknik ini harus sangat spesifik.
Martin York
3
@ Joachim: Ini digunakan untuk menghapus buffer secara cepat untuk rendering- secara kasar. Mereka hanya memiliki "bit yang jelas" per 64kb atau semacam itu.
DeadMG
3
@ user946850 "diamortisasi" berarti Anda dapat membuktikan bahwa operasi mahal jarang terjadi dalam gambar keseluruhan sehingga tidak berkontribusi lebih dari mis. O (1)

Jawaban:

2

Pendekatan yang disebutkan di atas mensyaratkan bahwa setiap sel dapat memiliki jumlah yang cukup besar untuk menampung berapa kali array mungkin perlu diinisialisasi ulang, yang merupakan penalti ruang yang substansial. Jika sebuah slot mampu memegang setidaknya satu nilai yang tidak akan pernah ditulis secara sah, seseorang dapat menghindari memiliki penalti ruang lain (tidak konstan) dengan mengorbankan menambahkan O(Wlg(N))penalti waktu, di mana Wjumlah slot array yang berbeda ditulis antara operasi kliring dan Nukuran array. Sebagai contoh, misalkan seseorang akan menyimpan bilangan bulat dari -2,147,483,647 ke 2,147,483,647 (tetapi tidak pernah -2,147,483,648) dan seseorang ingin item array kosong dibaca sebagai nol. Mulailah dengan mengisi array dengan -2,147.483.648 (sebut nilai ituB). Saat membaca slot array untuk aplikasi, laporkan nilai Bnol. Sebelum menulis Slot Array I, periksa apakah itu diadakan Bdan jika demikian dan Ilebih besar dari satu, menyimpan nol slot I/4setelah melakukan pemeriksaan serupa untuk lokasi itu (dan, jika diadakan B, I/16, dll).

Untuk menghapus array, mulailah dengan Isama dengan 0 atau 1, tergantung pada basis array (algoritma seperti yang dijelaskan akan bekerja untuk keduanya). Kemudian ulangi prosedur berikut: Jika item Iadalah Bkenaikan, Idan jika melakukannya menghasilkan kelipatan empat, bagi dengan empat (akhiri jika pembagian menghasilkan nilai 1); jika item Itidak B, simpan di Bsana dan kalikan Idengan empat (jika Idimulai dari nol, mengalikan dengan empat akan meninggalkannya nol, tetapi karena item 0 akan kosong, Iakan bertambah).

Perhatikan bahwa seseorang dapat mengganti konstanta "empat" di atas dengan angka lain, dengan nilai yang lebih besar umumnya membutuhkan lebih sedikit penandaan kerja, tetapi nilai yang lebih kecil umumnya membutuhkan lebih sedikit pembersihan kerja; karena slot array yang ditandai harus dihapus, nilai tiga atau empat hampir pasti optimal; karena nilai empat pasti dekat dengan optimal, lebih baik dari dua atau delapan, dan lebih nyaman daripada angka lainnya, itu akan menjadi pilihan yang paling masuk akal.

supercat
sumber
Cukup untuk memiliki penghitung versi yang mampu mengakomodasi pengaturan ulang berurutan yang cukup sebelum semua sel diperbarui dengan nilai segar. Dalam praktiknya satu byte mungkin cukup, atau bahkan kurang dalam loop yang lebih ketat.
9000
@ 9000: Kode yang bergantung pada perilaku seperti itu cenderung rapuh, terutama mengingat bahwa satu-satunya alasan untuk menggunakan pendekatan 'pseudo-clear' (bukan sekadar menghapus array) adalah jika set item yang akan membutuhkan yang akan dibersihkan biasanya kecil dan variabel - sepasang kondisi yang berkonspirasi untuk meningkatkan kemungkinan bahwa item dapat digunakan, "dibersihkan", dan kemudian tetap tidak tersentuh untuk waktu yang lama secara sewenang-wenang. Orang dapat mempertimbangkan memindai array dan secara fisik membersihkan slot lama ketika penghitung akan dibungkus, tapi ...
supercat
1
... jika nilai pembungkus penghitung adalah konstan, jumlah rata-rata pekerjaan untuk setiap operasi yang jelas array akan O (N), dengan N menjadi ukuran array. Bukan berarti hal seperti itu mungkin tidak berguna dalam praktik, karena implementasi O (N) yang dipercepat oleh faktor 65.536 masih akan menjadi O (N), tetapi juga akan menjadi 65.536 kali lebih cepat daripada yang tidak ditingkatkan. . Secara kebetulan, kasus-kasus di mana pendekatan ini akan membantu juga dapat mengambil manfaat dari menggunakan struktur data array-jarang, yang dapat menggunakan ruang O (AlgN) untuk menahan array dengan array ukuran N dengan elemen non-kosong.
supercat
1

Saya akan menyebutnya "lazy array sel reinitialization", tetapi tampaknya tidak memiliki nama mapan (yaitu, nama yang digunakan secara luas).

Algoritma ini cerdas, tetapi sangat terspesialisasi dan dapat diterapkan di area yang sangat sempit.

Aleksander Adamowski
sumber
1

Saya percaya ini adalah kasus khusus memoisasi , kecuali dalam kasus ini, "memo" secara implisit "usia" dengan setiap kenaikan dari penghitung global. Saya kira semacam "memo mundur".

defube
sumber