【问题标题】:How Can You Clear a Quad Tree Without Recursion ( using queue maybe? )如何在没有递归的情况下清除四叉树(可能使用队列?)
【发布时间】:2013-06-13 09:59:16
【问题描述】:

好的,给定一个类

class quadTree {
 short level;
 Vec2f midpoint;
 quadTree * nodes[4] = { NULL, NULL, NULL, NULL};

public:

void newPartition() {
 float j = fWIDTH  / 2 ^ level;
 float k = fHEIGHT / 2 ^ level;
  nodes[0] = new quadTree(level+1, midpoint[0] - j, midpoint[0] + k);
  nodes[1] = new quadTree(level+1, midpoint[0] + j, midpoint[0] + k);
  nodes[2] = new quadTree(level+1, midpoint[0] - j, midpoint[0] - k);
  nodes[3] = new qaudTree(level+1, midpoint[0] + j, midpoint[0] - k);
 }
}

我如何实现一个函数来删除四叉树当前节点下的所有节点而不使用可能使用队列的递归?就像在 Clear() 函数中一样。

对不起,我觉得我应该知道这一点,只是无法弄清楚。我在网上看了,但找不到任何东西。有什么想法吗?

对于任何使用队列的示例代码,只需使用 std::queue。

编辑:: 好的,我认为这就是我要用作参考的内容。我认为这应该可行,如果我错了,请纠正我。

#include <queue>
void helpClear( bool notPassing, queue<quadTree> &q ) {
int count;
for ( int i; i < 4; i++ ) {
 if ( node[i] != NULL){
  q.push ( node[i] );
  count++;
 }
}
quadTree * Point;
if ( notPassing ){
 for ( int i; i < count; i++ ){  
  Point = q.front();
  q.pop();
  Point -> helpClear(0, q);   
}
 for ( int i; i < 4; i ++ )
   delete nodes[i]; 
}
}

void clear () {
  queue <quadTree> q;
  quadTree * Point;
  helpClear(1,q);
  while (!queue.empty() ) {
    quadTree * Point;
    Point = q.front();
    q.pop();
    Point -> helpClear(1,q);
    delete Point;
  }
for ( int i; i < 4; i++ )
    nodes[i] = NULL;
}

helpClear() 是 quadTree 的私有函数,而 clear() 是您调用的公共函数,用于删除当前节点下的所有节点。

【问题讨论】:

  • 虽然避免递归通常不是一个坏主意,但我很确定这是一个很好的例子,“但避免递归并不总是一个好主意”。 - 在这种情况下,递归将比将要删除的对象堆叠到队列中然后删除队列要容易得多。
  • 我正在处理大量的四叉树和大量数据,这些数据可能会给堆栈带来不同的压力。我说的是如果我只是递归地调用他们的解构函数我可能会导致段错误的大小。你知道我该怎么做吗?
  • 这似乎很奇怪,因为四叉树的全部意义在于没有那么多层级,这使得递归相当浅。
  • Point = q.front(); q.pop(); 可以只是 Point = q.pop();。并且通常首选的方法是将其粘贴在析构函数中(它仍然是递归的,但这不太可能成为问题 - 10000 的深度对于递归应该没有问题,这意味着,对于一个有点平衡的树,更多的节点可能曾经可以放入内存(我的计算表明5*10^3624 个节点))。并且类名一般以大写字母开头 - QuadTree.
  • 您假设该程序堆栈中唯一的东西是四叉树,但事实并非如此。你也不能替换 Point = q.front(); q.pop();只需点 = q.pop(); cplusplus.com/reference/queue/queue/pop 不与 std::queue 一起使用。是的,我知道他们这样做,但我总是最终给他们小写的第一个单词,然后是大写的单词。这是一种习惯。

标签: c++ algorithm tree queue quadtree


【解决方案1】:

有两种思路(方法):

1) 如果您可以在一个点(例如,在顶层)控制所有newPartition()-actions,您可以实现quadTree 指针的特殊缓冲区并收集所有节点(@987654323 中的任何一个) @list, vector, queue, ...)。

在这种情况下,当您需要清理所有节点时,您可以通过此缓冲区中的指针来清理所有子节点,而无需使用堆栈。

2) 如果您的 QuadTree 使用严格的节点顺序(在空间意义上),您可以将所有指针组织在一个容器中。例如:

0级(1个指针):

1111
1111
1111
1111

1 级(4 个指针)

2233
2233
4455
4455

2级(16个指针)

ABEF
CDGH
IJMN
KLOP

在容器中的顺序是这样的:

12345ABCDEFGHIJKLOP

关卡之间的关系可以通过数学计算来解决,因为每个关卡都需要精确的 2^N 个元素。

此解决方案不需要额外的指针(和 0 指针),并解决您的堆栈问题。但是,从父级到子级以及从子级到父级需要更多时间,并且如果您在 QuadTree 中的级别不同(按其中之一中的元素数量,例如小于 2^N),可能会消耗更多内存。

注意:这是一种非常罕见的解决方案,在大多数情况下递归更好。

【讨论】:

  • 另一个很好的解决方案,但我希望能够在内存上尽可能轻松地做到这一点。谢谢,我确实考虑过这个,如果我放弃了,可能会求助于它。
  • 好的,这更清楚了,谢谢。我以为你的意思是在四叉树中有一个双重引用,在这个表中有另一个。
  • 这是一个morton索引,也叫z-order index,看我的回答。数据库使用这个技巧。
【解决方案2】:

某些应用程序可以使用四叉树,该四叉树被转换为具有键“morton Index”的数组。这样的四叉树是一个巨大的数组,没有任何子指针。 您可以像删除数组一样简单地删除它。

但并非所有应用程序都可以使用 MortonIndexed Quadtree。

但是递归应该没问题,因为四叉树的深度不应该超过 16。如果更深,那么你使用了错误类型的四叉树。

【讨论】:

    【解决方案3】:

    我使用自定义树实现来避免递归。在我的实现中,节点包含指向父节点、子节点和下一个普通(一级深度)节点的指针。使用这些数据很容易实现非递归树迭代。

    【讨论】:

    • 这是一个可行的解决方案,但那时我为什么不从堆中分配一个巨大的队列并将每个节点推入队列?这可能比每个节点最多保留 17 个额外的节点指针更有效(如果我理解你所说的下一个普通的意思)。我仍然可以将其减少到父节点的单个节点并使用我已经写过的东西。然而,这都是内存密集型的,我没有多余的内存,这是问题所在。
    猜你喜欢
    • 1970-01-01
    • 2011-09-08
    • 2017-05-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-04-08
    相关资源
    最近更新 更多