您有一個很好的解決方案(一個item-> node index)用於處理更新方法中的常見問題,這些更新方法源於需要使用舊邊界框刪除並使用新邊界框插入的問題。
插入方法是O(ln(N)),但項目停留在同一節點的更新可以在恆定時間內完成。移動到子節點也可以通過將搜索移除到當前持有該項目的節點來優化,並且移動到相鄰節點也可以消除一些此搜索,因爲每個節點都知道它的父節點。
我不知道Lua,所以請把下面的代碼視爲僞代碼。
function QuadTree:update(item)
oldNode = root.assignments[item]
newNode = oldNode:findNode(item)
if (oldNode ~= newNode) then
-- if findNode only searches down the tree newNode will be nil if
-- the item needs to move to/under an adjacent node. Otherwise the
-- next three lines are not needed
if (newNode == nil) then
newNode = root:findNode(item)
end
oldNode:remove(item)
newNode = newNode:insert(item)
end
return newNode
end
我不確定是否值得向上掃描樹。嘗試可能會很有趣,但只有在非常深的樹中才值得。
findNode方法通過自我掃描樹找到該項所屬的節點的空間位置。實現可以選擇只掃描自節點及其家屬:
-- Returns the node that the item belongs to by spatial location.
-- The tree can already contain the item. The item might be indexed using
-- an old geometry.
-- This method does not create child nodes.
function QuadTree:findNode(item)
local x,y,w,h = item:getBoundingBox()
if(not _contained(x,y,w,h , self:getBoundingBox())) then
-- Attempted to insert an item on a QuadTree that does not contain it;
-- just return
return nil
end
for _,node in ipairs(self.nodes) do
if(node:findNode(item) ~= nil) then return node end
end
return self
end
...或使用父節點,掃描整個樹:
-- Returns the node that the item belongs to by spatial location.
-- The tree can already contain the item. The item might be indexed using
-- an old geometry.
-- This method does not create child nodes.
function QuadTree:findNode(item)
local x,y,w,h = item:getBoundingBox()
if(not _contained(x,y,w,h , self:getBoundingBox())) then
-- Attempted to insert an item on a QuadTree that does not contain it;
-- scan the parent
if (parent == nil) then return nil end
return parent:findNode(item)
end
for _,node in ipairs(self.nodes) do
if(node:findNode(item) ~= nil) then return node end
end
return self
end
謝謝回答。幾何圖形是在四叉樹外部更新的 - 項目本身負責這樣做。你的例子的問題是oldNode:contains() - 即使它包含該項目,也可能是新節點是oldNode的子節點之一;例如,如果項目較小。我在試圖建模時遇到困難。 – kikito 2010-05-23 11:13:53
這是一個很好的觀點,我沒有說清楚:包含,移除和插入都可以是非遞歸實現,因爲它們正在處理的節點是正確的,即它們在Node上工作,而不是在Tree上工作沒有獨特的Node類。findNode必須在樹上遞歸地工作,它類似於插入,但沒有實際插入。 – richj 2010-05-23 11:22:13
第二個想法是,如果findNode沒有分割完整的節點會更好,因爲不是所有的findNode調用都跟着插入。我更新了僞代碼以允許newNode.insert(item)返回newNode的子節點。 – richj 2010-05-23 11:41:13