Квадрат з дублікатами


10

Я реалізую квадратик. Для тих, хто не знає цієї структури даних, я включаю наступний невеликий опис:

Квадрадерево є структурою даних , і в евклідовій площині , що октодерева знаходяться в 3-вимірному просторі. Поширеним використанням квадратиків є просторове індексування.

Підсумовуючи, як вони працюють, квадрати - це колекція - скажімо, прямокутників тут - з максимальною ємністю та початковою рамкою для обмеження. При спробі вставити елемент у квадратне дерево, яке досягло своєї максимальної ємності, квадратне дерево поділяється на 4 квадрата (геометричне зображення якого перед вставкою матиме в чотири рази меншу площу, ніж дерево); кожен елемент перерозподіляється в підрядках відповідно до свого положення, тобто. лівий верхній край при роботі з прямокутниками.

Отже, квадратик є або листям і має менше елементів, ніж його місткість, або дерево з 4 квадратами як діти (зазвичай північний захід, північний схід, південний захід, південний схід).

Моє занепокоєння полягає в тому, що якщо ви намагаєтеся додати дублікати, якщо це один і той же елемент кілька разів або кілька різних елементів з однаковою позицією, у чотиривіршків виникає принципова проблема з обробкою країв.

Наприклад, якщо ви працюєте з квадратом з ємністю 1 і одиничним прямокутником як обмежувальним полем:

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

І ви намагаєтесь двічі вставити прямокутник, у верхній лівій границі якого походження: (або аналогічно, якщо ви намагаєтесь вставити його N + 1 раз у квадратне дерево місткістю N> 1)

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

Перша вставка не буде проблемою: Спочатку вставити

Але тоді перша вставка запустить підрозділ (оскільки ємність дорівнює 1): Друга вставка, перший підрозділ

Обидва прямокутники, таким чином, поміщені в одне підкреслення.

Потім знову два елементи прийдуть в одне квадратне і запустить підрозділ ... Другий вкладиш, другий підрозділ

І так далі, і так далі, метод підрозділу буде працювати нескінченно, оскільки (0, 0) завжди буде знаходитися в одному підряді з чотирьох створених, тобто виникає нескінченна проблема рекурсії.

Чи можливо мати квадратик з дублікатами? (Якщо ні, то можна реалізувати це як Set)

Як ми можемо вирішити цю проблему, не порушивши повністю архітектури квадрату?


Як би ви хотіли, щоб він поводився? Ви реалізуєте це, тому вам доведеться вирішити, яка поведінка для вас правильна. Можливо, кожна унікальна координата може бути списком елементів у цій координаті. Можливо, ваші бали обмежені унікальністю. Ви знаєте, що вам потрібно, а ми - ні.
Марно

@Useless Це дуже правда. Однак, мабуть, було досить багато досліджень на цю тему, і я теж не хочу винаходити колесо. ТВН я до сих пір не знаю , чи належить це питання більше так, на programmers.SE, на gamedev.SE або навіть на math.SE ...
П'єр Arlaud

Відповіді:


3

Ви реалізуєте структуру даних, тому вам доведеться приймати рішення щодо впровадження.

Якщо у квадрату немає конкретного сказати про унікальність - і я не знаю, що це робиться - це рішення про реалізацію. Це є ортогональним для визначення квадрату, і ви можете вибрати, щоб обробляти його, як завгодно. Квадратура розповідає, як вставляти та оновлювати ключі, але не про те, чи вони повинні бути унікальними, або що ви можете приєднати до кожного вузла.

Прийняття рішень щодо впровадження - це не винахід колеса , принаймні не більше, ніж написання власної реалізації в першу чергу.

Для порівняння, стандартна бібліотека C ++ пропонує унікальний набір, не унікальний мультисет, унікальну карту (по суті, набір пар ключових значень, упорядкованих та порівнюваних лише за ключем) та не унікальну мультимапу. Всі вони, як правило, реалізовані за допомогою одного і того ж червоно-чорного дерева, і жодне не порушує архітектуру , просто тому, що визначення червоно-чорного дерева не має нічого сказати про унікальність ключів або типів, що зберігаються у вузлах листя.

Нарешті, якщо ви думаєте, що на цьому є дослідження, знайдіть його, і тоді ми можемо обговорити його. Можливо, є якийсь квадратурний інваріант, який я не помітив, або якесь додаткове обмеження, що дозволяє краще працювати.


Моя проблема полягає в тому, що я не можу знайти жодної документації, яка б зазначала, що унікальність є вимогою. Але якщо ви бачили мій приклад, ви можете бачити, що це справжня проблема, якщо ви кілька разів включаєте один і той же елемент.
П'єр Арло

Чи не стосується деревних типів структур, а також вузлу зі значенням іноді дається поле "count", яке просто збільшується та зменшується для дублікатів?
J Trana

2

Я думаю, тут є непорозуміння.

Як я розумію, кожен вузол квадратури містить значення, індексоване точкою. Іншими словами, вона містить потрійне (x, y, значення).

Він також містить 4 вказівника на дочірні вузли, які можуть бути нульовими. Між клавішами та дочірніми посиланнями існує алгоритмічна залежність.

Ваші вставки повинні виглядати так.

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

Перша вставка створює (батьківський) вузол і вставляє в нього значення.

Друга вставка створює дочірній вузол, посилається на нього і вставляє в нього значення (яке може статися таким же, як і перше значення).

Який дочірній вузол інстанціюється, залежить від алгоритму. Якщо алгоритм знаходиться у формі [x), а простір координат лежить у діапазоні [0,1), то кожна дитина буде охоплювати діапазон [0,0.5) і точка буде розміщена у дочірній сітці.

Я не бачу нескінченних рекурсій.


Отже, ви говорите про мій спосіб перерозподілу вузлів на дитячі квадри, коли підрозділяєте, що не так у моєму здійсненні?
П'єр Арло

Можливо, проблема полягає в тому, що ви намагаєтесь перенести значення з того місця, де воно знаходиться (у батьків) до кращого місця (у дитини). Це насправді не так, як це робиться. Значення добре там, де воно є. Але це призводить до цікавого результату, що дві однакові точки можна розміщувати в різних вузлах (але завжди пов'язаних між батьком і дитиною).
david.pfx

2

Загальна резолюція, з якою я стикався (у проблемах із візуалізацією, а не в іграх), полягає в тому, щоб викинути один з моментів, який завжди замінює або ніколи не замінює.

Я думаю, головний момент на користь - те, що це зробити легко.


2

Я припускаю, що ви індексуєте елементи приблизно однакового розміру, інакше життя стає складним, або повільним, або обом ……

Вузол квадратури не повинен мати фіксовану ємність. Ємність звикла

  • Дозволити фіксувати розмір кожного вузла дерева в пам'яті або на диску - не потрібно, якщо вузол дерева містить набір елементів змінного розміру і ви використовуєте систему розподілу простору, яка справляється. (Наприклад, java / c # об'єкти в пам'яті.)
  • Вирішіть, коли розділити вузол.
    • Ви можете просто переосмислити правило, щоб вузол був розбитий, якщо він містить більше, ніж “n” елементів району, де округ визначається відповідно до місця розташування елементів.
    • Або використовуйте " складений елемент", тож якщо в одному і тому ж місці є елементи множення, ви вводите новий елемент, що містить список цих елементів множення.

2

Коли ви маєте справу з проблемами просторової індексації, я фактично рекомендую починати з просторового хешу чи мого особистого фаворита: звичайної старої сітки.

введіть тут опис зображення

... і зрозуміти його слабкі місця спочатку, перш ніж перейти до деревних структур, які дозволяють розріджувати уявлення.

Однією з очевидних недоліків є те, що ви можете витрачати пам’ять на багато порожніх комірок (хоча пристойно реалізована сітка не повинна вимагати більше 32 біт на клітинку, якщо ви фактично не маєте мільярдів вузлів для вставки). Інше полягає в тому, що якщо у вас елементи середнього розміру, що більше розміру комірки, і часто налічують десятки комірок, ви можете витратити багато пам'яті, вставляючи ці елементи середнього розміру в набагато більше комірок, ніж ідеальних. Так само, коли ви робите просторові запити, вам, можливо, доведеться перевірити більше комірок, іноді набагато більше, ніж ідеальних.

Але єдине, що потрібно впорядкувати за допомогою сітки, щоб зробити її максимально оптимальною, оскільки це може бути проти певного вводу cell size, це не дає вам занадто багато думати і поспілкуватися, і тому це моя структура даних про перехід до даних для проблем просторової індексації, поки я не знайду причин не використовувати його. Це бруд простий у виконанні і не вимагає, щоб ви поспілкувалися з чим-небудь більш ніж одним вкладеним в експлуатацію.

Ви можете отримати багато з звичайної старої сітки, і я фактично переміг багато реалізацій квадратичного дерева та kd-дерева, що використовуються в комерційному програмному забезпеченні, замінивши їх на звичайну стару сітку (хоча вони не завжди були найкращими реалізованими , але автори витратили набагато більше часу, ніж 20 хвилин, які я витратив на збивання сітки). Ось швидка дрібничка, яку я пробув, щоб відповісти на запитання в іншому місці, використовуючи сітку для виявлення зіткнень (навіть не дуже оптимізовану, лише кілька годин роботи, і мені довелося витратити більшу частину часу, вивчаючи, як працює трафік, щоб відповісти на питання і вперше я здійснив виявлення зіткнень подібного роду):

введіть тут опис зображення

Ще одна слабкість сіток (але вони є загальною слабкістю для багатьох структур просторової індексації) полягає в тому, що якщо ви вставите безліч збігаються або перекриваються елементів, як і багато точок з однаковою позицією, вони будуть вставлені в точно ту саму клітинку ) та погіршують ефективність при проходженні цієї комірки. Аналогічно, якщо ви вставляєте багато масивних елементів, які набагато перевищують розмір комірок, вони захочуть вставити в човновий набір комірок і використовувати багато і багато пам’яті та погіршити час, необхідний для просторових запитів у всій дошці .

Однак ці дві негайні вище проблеми з збігом та масовими елементами насправді є проблематичними для всіх структур просторової індексації. Проста стара сітка насправді обробляє ці патологічні випадки трохи краще, ніж багато інших, оскільки вона, принаймні, не хоче рекурсивно підрозділяти клітини знову і знову.

Коли ви починаєте з сітки і рухаєтесь до чогось подібного до квадратичного дерева або KD-дерева, то головна проблема, яку ви хочете вирішити, - це проблема з тим, що елементи вставляються в занадто багато комірок, мають занадто багато комірок, і / або потрібно перевірити занадто багато комірок із таким типом щільного подання.

Але якщо ви думаєте про квадратичне дерево як оптимізацію через сіткудля конкретних випадків використання, то це допомагає все-таки думати про ідею "мінімального розміру комірок", щоб обмежити глибину рекурсивного підрозділу вузлів чотирьох дерев. Коли ви це зробите, найгірший сценарій квадратичного дерева все одно погіршиться в щільну сітку на листках, лише менш ефективну, ніж сітка, оскільки їй буде потрібно логарифмічний час, щоб пройти шлях від кореня до комірки сітки замість постійний час. І все ж думка про цей мінімальний розмір комірок дозволить уникнути нескінченного сценарію циклу / рекурсії. Для масивних елементів також є кілька альтернативних варіантів, таких як пухкі квадрати, які не обов'язково розбиваються рівномірно і можуть мати AABB для дочірніх вузлів, які перекриваються. BVH також цікаві як структури просторової індексації, які не розподіляють рівномірно свої вузли. Для збігу елементів проти деревних структур, головне - просто накласти обмеження на підрозділ (або, як запропонували інші, просто відхилити їх або знайти спосіб поводження з ними так, ніби вони не вносять до унікальної кількості елементів у листі, коли визначають, коли лист слід підрозділити). Дерево Kd також може бути корисним, якщо ви передбачаєте, що вводиться багато елементів, що збігаються, оскільки вам потрібно врахувати лише один вимір, визначаючи, чи повинен середній вузол розбиватися.


Як оновлення для quadtrees, хтось задав питання, яке було якесь широке (але мені це подобається) про те, як зробити їх ефективними для виявлення зіткнень, і я в кінцевому підсумку розлив мої кишки про те, як я їх реалізую. Він повинен також відповісти на ваші запитання: stackoverflow.com/questions/41946007 / ...
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.