C++ 查找树中的相邻节点

C++ 查找树中的相邻节点,c++,algorithm,tree,tree-traversal,C++,Algorithm,Tree,Tree Traversal,我正在开发一个类似于二叉树的结构,但它是跨维度的,因此您可以通过在初始化期间设置维度参数来设置它是否是二叉树、四叉树、八叉树等 以下是它的定义: template <uint Dimension, typename StateType> class NDTree { public: std::array<NDTree*, cexp::pow(2, Dimension)> * nodes; NDTree * parent; StateType sta

我正在开发一个类似于二叉树的结构,但它是跨维度的,因此您可以通过在初始化期间设置维度参数来设置它是否是二叉树、四叉树、八叉树等

以下是它的定义:

template <uint Dimension, typename StateType>
class NDTree {
public:
    std::array<NDTree*, cexp::pow(2, Dimension)> * nodes;
    NDTree * parent;
    StateType state;
    char position; //position in parents node list
    bool leaf;

    NDTree const &operator[](const int i) const
    {
        return (*(*nodes)[i]);
    }

    NDTree &operator[](const int i)
    {
        return (*(*nodes)[i]);
    }
}
我很难从任何一块中找到相邻的节点。它需要做的是确定一个方向,然后(如有必要)如果方向偏离父节点的边缘,则向上遍历树(例如,如果我们位于四叉树正方形的右下角,需要将该块移到其右侧)。我的算法返回假值

以下是阵列的布局方式:

以下是需要了解的结构:

这只是保持项目的方向

enum orientation : signed int {LEFT = -1, CENTER = 0, RIGHT = 1};
这有一个方向,以及是否要更深入

template <uint Dimension>
struct TraversalHelper {
    std::array<orientation, Dimension> way;
    bool deeper;
};
例如:

std::array<orientation, Dimension> direction;
direction[0] = LEFT; //x
direction[1] = CENTER; //y

NDTree<Dimension> * result = tree[3][0]->getAdjacentNode(direction);
有更多不正确行为的示例,例如树[0][0](左,左),但其他许多操作都是正确的


是我正在处理的git回购的文件夹。如果有必要,只需从该目录运行
g++-std=c++11 main.cpp

在八叉树中查看邻居搜索的答案:。基本上,您需要在节点中记录从根节点到节点的遍历,并操纵此信息以生成所需的遍历以到达相邻节点。

以下是您可以尝试利用的一个属性: 仅考虑4个节点:

 00  01
 10  11
任何节点最多可以有4个邻居节点;两个将存在于同一个结构中(较大的正方形),您必须在相邻结构中查找其他两个。 让我们重点识别相同结构中的邻居:00的邻居是01和10;11的邻居是01和10。请注意,相邻节点之间只有一位不同,并且可以在水平和垂直方向上对相邻节点进行分类。所以

     00 - 01    00 - 01    //horizontal neighbors
     |               |
     10              11    //vertical neighbors
请注意,翻转MSB如何获得垂直邻居,翻转LSB如何获得水平节点?让我们仔细看看:

   MSB:  0 -> 1 gets the node directly below
         1 -> 0 sets the node directly above

   LSB:  0 -> 1 gets the node to the right
         1 -> 0 gets the node to the left
现在我们可以确定每个方向上的节点,假设它们存在于同一个子结构中。00或10以上左侧的节点如何??根据目前的逻辑,如果你想要一个水平的邻居,你应该翻转LSB;但翻转它将检索10(右侧的节点)。因此,让我们为不可能的操作添加一条新规则:

   you can't go left for  x0 , 
   you can't go right for x1,
   you can't go up for    0x,
   you can't go down for  1x
*不可能操作是指同一结构内的操作。 让我们看一看更大的图景,哪一个是00的左邻右舍?如果我们向左走到结构0(S0)的00,我们应该得到(S1)的01,如果我们向上走,我们得到S(2)的节点10请注意,它们基本上是相同的水平/真实相邻值形式S(0),只是它们在不同的结构中。因此,基本上,如果我们知道如何从一个结构跳到另一个结构,我们就有了一个算法。 让我们回到我们的示例:从节点00(S0)向上。我们应该在S2结束;所以再次00->10翻转MSB。因此,如果我们在结构中使用相同的算法,我们应该会很好

底线: 结构中的有效转换

MSB 0, go down
  1, go up
LSB 0, go right
  1, go left

for invalid transitions (like MSB 0, go up)
determine the neighbor structure by flipping the MSB for vertical and LSB for vertical
and get the neighbor you are looking for by transforming a illegal move in structure A
into a legal one in strucutre B-> S0: MSB 0 up, becomes S2:MSB 0 down.   

我希望这个想法足够明确

我能想到的最简单的答案是从树的根返回节点

可以为每个单元分配一个坐标映射到树的最深节点。在您的示例中,(x,y)坐标的范围为0到2维-1,即0到3

首先,使用您喜欢的任何算法计算邻居的坐标(例如,决定从边缘向右移动是否应换行到同一行的第一个单元格,向下移动到下一行或保持不变)

然后,将新坐标输入常规搜索函数。它将以
维度
步骤返回相邻单元格

您可以通过查看坐标的二进制值来优化它。基本上,最显著差异的等级告诉你应该提升多少级别

例如,让我们取一个深度为4的四叉树。坐标范围从0到15

假设我们从5号牢房(0101b)向左走。新坐标为4(0100b)。更改的最高有效位是位0,这意味着您可以在当前块中找到邻居

现在如果你向右走,新的坐标是6(0110b),因此改变影响了位1,这意味着你必须上升一级才能访问你的单元格


尽管如此,使用这些技巧所需的计算时间和代码量对我来说似乎不值得付出任何努力。

谢谢你的链接;有了这种结构,就没有一个静态根(并且为一个新根更新所有节点的成本非常高)。我必须从当前节点向上而不是自上而下执行本地方法。然后,通过向上走直到找到根,您可以在我引用的答案(从根到节点的遍历记录)中生成所谓的“nD索引”。并且对所需邻居的“nD索引”的计算仍然适用,以及相应的遍历以找到该邻居;我知道,如果节点的父节点列表中有可用的位置(例如父节点、位置和子节点),则不必一直向上移动。每次都有大约1/2^n的机会实际上升到更高的水平,因此在默认情况下走完整的路线需要做大量额外的工作。您可能不必使用“nD index”解决方案一直走到根。当查询节点的“nD索引”完全已知时,该索引只需简单地递增/递减即可获得节点邻居的“nD索引”。现在,当您从查询节点沿着树向上走时,您正在逐步恢复这个“nD索引”。只要部分“nD索引”的增量/减量不再携带/借用(在基数2中),那么您可以
     00 - 01    00 - 01    //horizontal neighbors
     |               |
     10              11    //vertical neighbors
   MSB:  0 -> 1 gets the node directly below
         1 -> 0 sets the node directly above

   LSB:  0 -> 1 gets the node to the right
         1 -> 0 gets the node to the left
   you can't go left for  x0 , 
   you can't go right for x1,
   you can't go up for    0x,
   you can't go down for  1x
MSB 0, go down
  1, go up
LSB 0, go right
  1, go left

for invalid transitions (like MSB 0, go up)
determine the neighbor structure by flipping the MSB for vertical and LSB for vertical
and get the neighbor you are looking for by transforming a illegal move in structure A
into a legal one in strucutre B-> S0: MSB 0 up, becomes S2:MSB 0 down.