虽然我尝试以二叉树遍历的方式接近它,但我无法弄清楚迭代八叉树遍历的过程。对于我的问题,我有八个节点有子指针和父指针,我想迭代并只将叶节点存储在堆栈中。 此外,迭代遍历比递归遍历要快吗?
答案 0 :(得分:5)
它确实像二叉树遍历,但您需要存储一些中间信息。递归算法本身不会更慢,但是对于O(log8)递归调用使用更多的堆栈空间(对于八叉树中的10亿个元素,大约10个级别)。 迭代算法也需要相同数量的空间才能有效,但您可以将它放入堆中,因为您担心堆栈可能会溢出。
递归你会做(伪代码):
function traverse_rec (octree):
collect value // if there are values in your intermediate nodes
for child in children:
traverse_rec (child)
获得迭代算法的最简单方法是首先使用堆栈或队列进行深度处理或首先进行呼吸:
function traverse_iter_dfs(octree):
stack = empty
push_stack(root_node)
while not empty (stack):
node = pop(stack)
collect value(node)
for child in children(node):
push_stack(child)
用队列替换堆栈,然后先进行呼吸搜索。但是,我们在O(7 *(log8 N))节点的区域中存储了一些我们尚未遍历的节点。如果你考虑一下,那就是较小的邪恶,除非你需要遍历真正的大树。唯一的另一种方法是使用父指针,当你在一个孩子完成后,然后你需要以某种方式选择下一个兄弟。
如果你没有提前存储当前节点的索引(就其兄弟姐妹而言),你只能搜索父节点的所有节点,以便找到下一个兄弟节点,这实际上是两倍于要完成的工作(对于每个节点,您不仅要遍历子节点,还要通过兄弟节点)。此外,看起来你至少需要记住你已经访问过哪些节点,因为它通常是不可判定的,是否要向下移动或者返回树上(否则证明我错了)。
总而言之,我建议不要寻找这样的解决方案。
答案 1 :(得分:0)
取决于您的目标。您是否尝试查找节点是否可见,光线是否与其边界框相交,或者节点中是否包含某个点?
假设你正在做最后一个,检查一个点是否应该包含在节点中。我会向Octnode添加一个方法,它接受一个点并检查它是否位于Octnode的边界框内。如果确实返回true,则返回false,非常简单。从这里开始,调用一个从头节点开始的向下钻取方法并检查每个子节点,简单的“for”循环,看看它所在的Octnode,它最多只能是一个。
这是您的迭代与递归算法发挥作用的地方。如果您想要迭代,只需将指针存储到当前节点,并将此指针从头节点交换到包含您的点的节点。然后继续向下钻取,直到达到最大深度或者找不到包含它的Octnode。如果你想要一个递归解决方案,那么你将在Octnode上调用这个向下钻取方法,你找到了这个点。
我不会说迭代与递归在速度方面有很大的性能差异,但它在内存性能方面可能有所不同。每次递归时,都会在堆栈中添加另一个调用深度。如果你有一个大的八叉树,这可能会导致大量的调用,可能会导致你的堆栈。