4

Я реализую динамическое kD-Tree в представлении массива (сохраняя узлы в std :: vector) в ширину. Каждый i-й нелистовой узел имеет левого ребенка в (i<<1)+1 и право ребенка в (i<<1)+2. Он будет поддерживать инкрементную вставку точек и сбор очков. Однако я столкнулся с проблемой определения необходимого количества возможных узлов для постепенного предварительного выделения пространства.Предскажите необходимое количество предварительно распределенных узлов в kD-дереве

Я нашел formula on the web, который, как представляется неправильным:

N = мин (т - 1, 2n - ½m - 1),

где т является наименьшей степенью 2 больше или равно n, число точек .

Моя реализация формулы заключается в следующем:

size_t required(size_t n) 
{ 
    size_t m = nextPowerOf2(n); 
    return min(m - 1, (n<<1) - (m>>1) - 1); 
} 

функция nextPowerOf2 возвращает мощность 2 по величине или равной п

Любая помощь будет оценена.

+2

Вы должны сначала попытаться поделиться своими мыслями с автором блога. –

+0

Вы пробовали с небольшим количеством баллов, чтобы узнать, где ошибка? Какова была ошибка, недостаточно предварительно выделенных объектов? Не могли бы вы поместить фактические значения .. например: я попытался с точками 'X' ...' m' рассчитывал: 'Y' и' required' возвращал значение 'Z' .. но в конце мне нужно было' W' – wendelbsilva

+0

, так как вопрос о количестве требуемых узлов, да, ошибка - это недостаточно предварительно выделенные узлы, что приводит к segfault. Я протестировал алгоритм с фактическими значениями, он работает, однако заканчивается из хранилища. – plasmacel

ответ

1

Каждый узел kd-дерева делит пространство на два пробела. Следовательно, количество узлов в kd-дереве зависит от того, как вы выполняете это разделение:

1) Если вы разделите их в середине пространства (то есть, если пространство от x1 до x2, вы разделите пространство с линией x3 = (x1 + x2)/2), то: i) Каждая точка будет выделена собственным узлом, а ii) Каждый промежуточный узел будет пустым.

В этом случае количество узлов будет зависеть от того, насколько велики координаты точек. Если координаты ограничены | X |, то общее число узлов в kd-дереве должно быть немного меньше, чем log | X | * n (точнее, вокруг log | X | * n - n log n + 2n) в худшем случае. Чтобы увидеть это, рассмотрим следующий способ добавления точек: вы добавляете несколько коллекций, каждая коллекция имеет два чрезвычайно близких точки, расположенных наугад. Для каждой пары точек дерево необходимо будет непрерывно делить пространство log | X | раз, и если log | X | значительно больше, чем log n, создавая log | X | промежуточные узлы в процессе.

2) Если вы разделите их, используя точку в качестве разделительной линии, то каждый узел (включая промежуточные узлы) будет содержать точку. Таким образом, общее число узлов - просто n. Однако обратите внимание, что использование точки для разделения пространства может привести к очень плохой производительности, если точки не заданы в случайном порядке (например, если точки указаны в порядке возрастания X, глубина дерева будет O (n). Для сравнения, глубина дерева в (1) не превосходит O (log | X |)).

+0

В вашем случае 2 вы предполагаете, что kd-дерево делит точку на чередующееся правило оси круговой оси, что может привести к неэффективности, как вы заявили. Однако это поведение - это только эффект переменного правила, но не метод «делить их с использованием точки как разделительной линии». Я использую крайнее крайнее правило края (подразделение точки на наибольшее измерение их выровненной по оси ограничительной рамки) для подразделения, свободного от этого поведения. – plasmacel

+0

Кроме того, верно, что фактическое число узлов равно количеству точек. Однако помните, что kD-Tree в представлении массива в первом порядке. Каждый i-й узел имеет левый дочерний элемент в (i << 1) +1 и правый ребенок в (i << 1) +2. Поэтому узлам не требуется явно хранить их детей влево/вправо. Это представление является кэшируемым, в отличие от связанного списка. В этом конкретном случае вам необходимо выделить больше места, чем вам нужно, потому что теоретически каждый узел может иметь левый и/или правый дочерние элементы на i + 1 и i + 2, которые вы не можете предсказать. – plasmacel

+0

@plasmacel Справа, которую я забыл. В этом случае вы, скорее всего, не сможете использовать случай 1, так как требуемая память теперь будет O (| X |). Кстати, если вы используете самое длинное правило края, я предполагаю, что вы разделите пространство на их середину? В этом случае вещи, которые я сказал в случае 1, имеют место. Если вы воспользуетесь случаем 2 (используйте точку, чтобы разделить пространство на их самой длинной оси), то точки на корпусе 2 все еще сохраняются, а именно, если точки вставлены в наихудший возможный случай, глубина дерева равна O (N), что требует 2^N памяти. – Irvan

Смежные вопросы