Quadtree dengan duplikat


10

Saya menerapkan quadtree. Bagi mereka yang tidak mengetahui struktur data ini, saya menyertakan deskripsi kecil berikut:

Sebuah Quadtree adalah struktur data dan pada bidang Euclidean apa octree berada dalam ruang 3-dimensi. Penggunaan quadtrees yang umum adalah pengindeksan spasial.

Untuk meringkas cara kerjanya, quadtree adalah koleksi - katakanlah persegi panjang di sini - dengan kapasitas maksimum dan kotak pembatas awal. Ketika mencoba memasukkan elemen ke dalam quadtree yang telah mencapai kapasitas maksimalnya, quadtree dibagi menjadi 4 quadtree (representasi geometris yang akan memiliki area empat kali lebih kecil dari pohon sebelum penyisipan); setiap elemen didistribusikan kembali di sub-sub pohon sesuai dengan posisinya, yaitu. terikat kiri atas saat bekerja dengan persegi panjang.

Jadi quadtree adalah daun dan memiliki elemen kurang dari kapasitasnya, atau pohon dengan 4 quadtree sebagai anak-anak (biasanya barat laut, timur laut, barat daya, tenggara).

Kekhawatiran saya adalah bahwa jika Anda mencoba untuk menambahkan duplikat, mungkin itu elemen yang sama beberapa kali atau beberapa elemen berbeda dengan posisi yang sama, quadtrees memiliki masalah mendasar dengan penanganan ujung-ujungnya.

Misalnya, jika Anda bekerja dengan quadtree dengan kapasitas 1 dan persegi panjang unit sebagai kotak pembatas:

[(0,0),(0,1),(1,1),(1,0)]

Dan Anda mencoba memasukkan dua kali persegi panjang batas kiri atas yang merupakan asal: (atau serupa jika Anda mencoba memasukkannya N + 1 kali dalam quadtree dengan kapasitas N> 1)

quadtree->insert(0.0, 0.0, 0.1, 0.1)
quadtree->insert(0.0, 0.0, 0.1, 0.1)

Sisipan pertama tidak akan menjadi masalah: Masukkan pertama

Tetapi kemudian insert pertama akan memicu subdivisi (karena kapasitasnya 1): Sisipan kedua, pembagian pertama

Kedua persegi panjang dengan demikian diletakkan di subtree yang sama.

Kemudian lagi, dua elemen akan tiba di quadtree yang sama dan memicu subdivison ... Sisipan kedua, subdivison kedua

Dan seterusnya, dan seterusnya, metode pembagian akan berjalan tanpa batas karena (0, 0) akan selalu berada di subtree yang sama dari empat yang dibuat, yang berarti masalah rekursi tak terbatas terjadi.

Apakah mungkin untuk memiliki quadtree dengan duplikat? (Jika tidak, seseorang dapat menerapkannya sebagai a Set)

Bagaimana kita bisa menyelesaikan masalah ini tanpa menghancurkan sepenuhnya arsitektur quadtree?


Bagaimana Anda ingin berperilaku? Anda menerapkannya, jadi Anda harus memutuskan perilaku apa yang benar untuk Anda. Mungkin setiap koordinat unik dapat menjadi daftar elemen pada koordinat itu. Mungkin poin Anda dibatasi menjadi unik. Anda tahu apa yang Anda butuhkan, dan kami tidak.
berguna

@ Tidak Berguna Itu sangat benar. Namun pasti ada banyak penelitian tentang topik ini dan saya tidak benar-benar ingin menemukan kembali roda. TBH Saya masih tidak tahu apakah pertanyaan ini lebih pada SO, pada programmer.SE, pada gamedev.SE atau bahkan pada math.SE…
Pierre Arlaud

Jawaban:


3

Anda menerapkan struktur data, jadi Anda harus membuat keputusan implementasi.

Kecuali jika quadtree memiliki sesuatu yang spesifik untuk dikatakan tentang keunikan - dan saya tidak tahu itu - ini adalah keputusan implementasi. Ini ortogonal dengan definisi quadtree dan Anda dapat memilih untuk menanganinya sesuka Anda. Quadtree memberi tahu Anda cara memasukkan dan memperbarui kunci, tetapi tidak apakah kunci itu harus unik, atau apa yang dapat Anda lampirkan pada setiap node.

Membuat keputusan implementasi bukanlah menciptakan kembali roda , paling tidak tidak lebih dari menulis implementasi Anda sendiri sejak awal.

Sebagai perbandingan, pustaka standar C ++ menawarkan set unik, multiset non-unik, peta unik (pada dasarnya seperangkat pasangan nilai-kunci yang dipesan & dibandingkan hanya dengan kunci) dan multimap non-unik. Mereka semua biasanya diimplementasikan menggunakan pohon merah-hitam yang sama dan tidak ada yang melanggar arsitektur , hanya karena definisi pohon merah-hitam tidak ada yang mengatakan tentang keunikan kunci atau jenis yang disimpan dalam node daun.

Akhirnya, jika Anda berpikir ada penelitian tentang ini, temukan, dan kemudian kita bisa membahasnya. Mungkin ada beberapa quadtree invarian yang saya abaikan, atau beberapa kendala tambahan yang memungkinkan kinerja yang lebih baik.


Masalah saya adalah saya tidak dapat menemukan dokumentasi yang menyatakan bahwa keunikan adalah persyaratan. Namun, jika Anda telah melihat contoh saya, Anda dapat melihat itu masalah nyata jika Anda memasukkan beberapa kali elemen yang sama.
Pierre Arlaud

Untuk jenis struktur pohon, bukankah simpul dengan nilai terkadang juga diberi bidang "hitung" yang hanya menambah dan mengurangi duplikat?
J Trana

2

Saya pikir ada kesalahpahaman di sini.

Seperti yang saya pahami, setiap simpul quadtree berisi nilai yang diindeks oleh suatu titik. Dengan kata lain, ini mengandung triple (x, y, value).

Ini juga berisi 4 pointer ke node anak, yang mungkin nol. Ada hubungan algoritmik antara kunci dan tautan anak.

Sisipan Anda akan terlihat seperti ini.

quadtree->insert(0.0, 0.0, value1)
quadtree->insert(0.0, 0.0, value2)

Sisipan pertama membuat simpul (induk) dan memasukkan nilai ke dalamnya.

Sisipan kedua membuat simpul anak, menautkannya, dan memasukkan nilai ke dalamnya (yang mungkin sama dengan nilai pertama).

Node anak mana yang dipakai tergantung pada algoritma. Jika algoritma dalam bentuk [x) dan ruang koordinat terletak pada kisaran [0,1) maka setiap anak akan rentang rentang [0,0,5) dan titik akan ditempatkan pada anak NW.

Saya tidak melihat rekursi yang tak terbatas.


Jadi Anda mengatakan cara saya mendistribusikan kembali node ke quadtrees anak-anak ketika membagi adalah apa yang salah dengan implemantasi saya?
Pierre Arlaud

Mungkin masalahnya adalah Anda mencoba untuk memindahkan nilai dari tempat itu (di orangtua) ke tempat yang lebih baik (di anak-anak). Ini sebenarnya bukan bagaimana itu dilakukan. Nilainya baik-baik saja di tempat itu. Tapi itu memang mengarah pada hasil yang menarik bahwa dua titik identik dapat ditempatkan di node yang berbeda (tetapi selalu terkait orangtua dan anak).
david.pfx

2

Resolusi umum yang saya temui (dalam masalah visualisasi, bukan dalam game) adalah membuang salah satu poin, baik selalu mengganti atau tidak pernah mengganti.

Saya kira poin utama yang mendukung adalah bahwa hal itu mudah dilakukan.


2

Saya berasumsi bahwa Anda sedang mengindeks elemen-elemen yang berukuran hampir sama, jika tidak hidup menjadi kompleks, atau lambat, atau keduanya ……

Node Quadtree tidak perlu memiliki kapasitas tetap. Kapasitas digunakan untuk

  • Izinkan setiap simpul pohon menjadi ukuran tetap dalam memori atau pada disk - tidak diperlukan jika simpul pohon berisi kumpulan elemen berukuran variabel dan Anda menggunakan sistem alokasi ruang yang berupaya. (Misalnya objek java / c # dalam memori.)
  • Putuskan kapan harus membagi node.
    • Anda bisa mendefinisikan ulang aturan, sehingga sebuah node terpecah jika mengandung lebih dari "n" elemen distrik, di mana distrik didefinisikan sesuai dengan lokasi elemen.
    • Atau gunakan " elemen komposit ", jadi jika ada elemen gandakan di lokasi yang sama, Anda memperkenalkan elemen baru yang berisi daftar elemen gandakan ini.

2

Ketika Anda berurusan dengan masalah pengindeksan spasial, saya benar-benar merekomendasikan memulai dengan hash spasial atau favorit pribadi saya: grid lama polos.

masukkan deskripsi gambar di sini

... dan pahami kelemahannya terlebih dahulu sebelum pindah ke struktur pohon yang memungkinkan representasi yang jarang.

Salah satu kelemahan yang jelas adalah bahwa Anda dapat membuang-buang memori pada banyak sel kosong (meskipun grid yang diterapkan dengan baik seharusnya tidak memerlukan lebih dari 32-bit per sel kecuali Anda benar-benar memiliki miliaran node untuk dimasukkan). Lain adalah bahwa jika Anda memiliki elemen berukuran sedang yang lebih besar dari ukuran sel dan sering span, katakanlah, puluhan sel, Anda dapat membuang banyak memori memasukkan elemen berukuran sedang ke sel-sel jauh lebih banyak daripada yang ideal. Demikian juga ketika Anda melakukan kueri spasial, Anda mungkin harus memeriksa lebih banyak sel, terkadang jauh lebih banyak, dari yang ideal.

Tetapi satu-satunya hal yang perlu dilakukan dengan kisi-kisi untuk membuatnya seoptimal mungkin terhadap input tertentu adalah cell size, yang tidak membuat Anda terlalu banyak berpikir dan mengotak-atik, dan itulah mengapa struktur data saya masuk ke struktur untuk masalah pengindeksan spasial sampai saya menemukan alasan untuk tidak menggunakannya. Sangat mudah diterapkan dan tidak mengharuskan Anda mengutak-atik apa pun selain input runtime tunggal.

Anda bisa mendapatkan banyak dari grid lama biasa dan saya benar-benar telah mengalahkan banyak implementasi quad-tree dan kd tree yang digunakan dalam perangkat lunak komersial dengan menggantinya dengan grid lama polos (meskipun mereka belum tentu yang terbaik diimplementasikan , tetapi penulis menghabiskan lebih banyak waktu daripada 20 menit yang saya habiskan untuk menyiapkan kotak). Ini adalah hal kecil cepat yang saya siapkan untuk menjawab pertanyaan di tempat lain menggunakan kisi-kisi untuk deteksi tabrakan (bahkan tidak benar-benar dioptimalkan, hanya beberapa jam kerja, dan saya harus menghabiskan sebagian besar waktu mempelajari cara kerja pathfinding bekerja untuk menjawab pertanyaan tersebut dan ini juga pertama kalinya saya menerapkan deteksi tabrakan semacam ini):

masukkan deskripsi gambar di sini

Kelemahan lain dari grid (tetapi mereka adalah kelemahan umum untuk banyak struktur pengindeksan spasial) adalah bahwa jika Anda memasukkan banyak elemen yang bertepatan atau tumpang tindih, seperti banyak titik dengan posisi yang sama, mereka akan dimasukkan ke dalam sel yang sama persis (s). ) dan menurunkan kinerja saat melintasi sel itu. Demikian pula jika Anda memasukkan banyak elemen masif yang jauh, jauh lebih besar dari ukuran sel, mereka akan ingin dimasukkan ke dalam muatan kapal sel dan menggunakan banyak dan banyak memori dan menurunkan waktu yang diperlukan untuk pertanyaan spasial di seluruh papan. .

Namun, dua masalah langsung di atas dengan elemen coincident dan massif sebenarnya bermasalah untuk semua struktur pengindeksan spasial. Grid tua polos sebenarnya menangani kasus-kasus patologis ini sedikit lebih baik daripada banyak yang lain karena setidaknya tidak ingin membagi sel secara rekursif berulang-ulang.

Ketika Anda mulai dengan kisi dan bekerja menuju sesuatu seperti quad-tree atau KD-tree, maka masalah utama yang ingin Anda pecahkan adalah masalah dengan elemen yang dimasukkan ke terlalu banyak sel, memiliki terlalu banyak sel, dan / atau harus memeriksa terlalu banyak sel dengan tipe representasi padat ini.

Tetapi jika Anda menganggap quad-tree sebagai optimasi di atas kisiuntuk kasus penggunaan tertentu, maka masih membantu untuk memikirkan gagasan "ukuran sel minimum", untuk membatasi kedalaman subdivisi rekursif node quad-tree. Ketika Anda melakukan itu, skenario terburuk dari quad-tree masih akan terdegradasi ke grid padat di daun, hanya kurang efisien daripada grid karena akan membutuhkan waktu logaritmik untuk bekerja jauh dari root ke cell cell daripada waktu konstan. Namun memikirkan ukuran sel minimum itu akan menghindari skenario loop / rekursi yang tak terbatas. Untuk elemen masif ada juga beberapa varian alternatif seperti quad-tree longgar yang tidak perlu membelah secara merata dan dapat memiliki AABB untuk node anak yang tumpang tindih. BVH juga menarik sebagai struktur pengindeksan spasial yang tidak membagi node secara merata. Untuk elemen yang bertepatan dengan struktur pohon, yang utama adalah memaksakan batasan pada subdivisi (atau seperti yang disarankan orang lain, hanya menolaknya, atau menemukan cara untuk memperlakukannya seolah-olah mereka tidak berkontribusi pada jumlah elemen unik dalam daun ketika menentukan kapan daun harus membagi). Pohon Kd mungkin juga berguna jika Anda mengantisipasi input dengan banyak elemen bertepatan, karena Anda hanya perlu mempertimbangkan satu dimensi ketika menentukan apakah sebuah node harus median split.


Sebagai pembaruan untuk quadtrees, seseorang mengajukan pertanyaan yang agak luas (tapi saya suka itu) tentang bagaimana membuatnya efisien untuk deteksi tabrakan, dan saya akhirnya menumpahkan nyali saya pada yang satu itu tentang bagaimana saya menerapkannya. Itu juga harus menjawab pertanyaan Anda: stackoverflow.com/questions/41946007/…
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.