Массовая загрузка точки дерева
Я реализовал метод массовой загрузки точечного дерева квадрантов. Но для некоторых входных данных это не работает правильно, например, если есть много точек, которые имеют одинаковую координату x или y. Пример набора данных:
test = [(3, 1), (16, 1), (11, 4), (5, 4), (9, 6), (5, 10),
(1, 15), (11, 5), (11, 15), (12, 16), (19, 17)]
tree = create(test)
Проблема возникает в точках: (11,4),(11,5),(11,15)
а также (5,10),(5,4)
,
Это create
функция:
def create(point_list, presorted=False):
if not point_list:
return QuadNode()
if not presorted:
point_list.sort(key=lambda p: [p[0],p[1]])
median = len(point_list) >> 1
relevantPoint = point_list[median]
relevantYCoordinate = relevantPoint[1]
node = QuadNode(data=relevantPoint)
leftBins = point_list[:median]
rightBins = point_list[median + 1:]
nwBins = [bin for bin in leftBins if bin[1] >= relevantYCoordinate]
swBins = [bin for bin in leftBins if bin[1] < relevantYCoordinate]
neBins = [bin for bin in rightBins if bin[1] >= relevantYCoordinate]
seBins = [bin for bin in rightBins if bin[1] < relevantYCoordinate]
node.nwNode = create(nwBins, presorted=True)
node.swNode = create(swBins, presorted=True)
node.neNode = create(neBins, presorted=True)
node.seNode = create(seBins, presorted=True)
return node
и QuadNode
:
class QuadNode(object):
def __init__(self, data=None, nwNode=None, neNode=None, swNode=None, seNode=None):
self.data = data
self.nwNode = nwNode
self.neNode = neNode
self.swNode = swNode
self.seNode = seNode
Я хочу следовать правилу для вставки, удаления и т.д.:
swNode
point.x < parent.x
а такжеpoint.y < parent.y
seNode
point.x >= parent.x
а такжеpoint.y < parent.y
nwNode
point.x < parent.x
а такжеpoint.y >= parent.y
neNode
point.x >= parent.x
а такжеpoint.y >= parent.y
1 ответ
Ваш метод выбора середины является правильным (как объяснено в оригинальной статье Finkel Quadtrees: структура данных для извлечения по составным ключам), но способ построения подколлекций для поддеревьев неверен.
Например, с этим отсортированным списком:
[(1, 1), (1, 2), (1, 3)]
медиана 1, 2
и, учитывая ваши правила для границ, 1,1
должен быть в SE и 1,3
в NE.
В оригинальной статье SE и NW "открыты", а NW и SE закрыты: 1,1
находится в северо-западе и 1,3
в ЮВ Как вы можете видеть из этого определения границ, все элементы до медианы будут в SE или NW, а все элементы после медианы будут в SW или NE. Но это не относится к вашему определению границ.
Так что либо с определением ваших границ что-то не так, либо вы должны проверить каждый элемент списка, чтобы убедиться, что он попадает в нужную область. Для примера:
relevantPoint = point_list[median]
node = QuadNode(data=relevantPoint)
del point_list[median]
nwBins = [(x,y) for x,y in point_list if x < relevantPoint[0] and y >= relevantPoint[1]]
swBins = [(x,y) for x,y in point_list if x < relevantPoint[0] and y < relevantPoint[1]]
seBins = [(x,y) for x,y in point_list if x >= relevantPoint[0] and y <= relevantPoint[1]]
neBins = [(x,y) for x,y in point_list if x <= relevantPoint[0] and y > relevantPoint[1]]
Однако это довольно уродливо и не гарантирует, что дерево будет сбалансировано. Я бы лучше проверил определение границ....