在树的节点上构建等价类的好数据结构是啥?

Posted

技术标签:

【中文标题】在树的节点上构建等价类的好数据结构是啥?【英文标题】:What's a good data structure for building equivalence classes on nodes of a tree?在树的节点上构建等价类的好数据结构是什么? 【发布时间】:2009-03-23 19:17:20 【问题描述】:

我正在寻找一种好的数据结构来在树的节点上构建等价类。在理想的结构中,以下操作应该是快速的(O(1)/O(n),视情况而定)并且容易(没有神秘代码段落):

(A) 从树根出发;在每个节点上 --> 子转换枚举子节点的所有等效版本 (B) 合并两个等价类 (C) 从现有节点(子节点)和其他数据的列表中创建新节点 (D) 找到任何结构上与node 等价的节点(即它们具有相同数量的子节点,对应的子节点属于相同的等价类,并且它们的“其他数据”相同)使得新的(或新修改的)节点可以放在正确的等价类中(通过合并)

到目前为止我已经考虑过(其中一些可以组合使用):

冻糕,其中子代是对节点集合的引用,而不是对节点的引用。 (A) 速度快,(B) 需要遍历树并更新节点以指向合并的集合,(C) 需要找到包含新节点的每个子节点的集合,(D) 需要遍历树 根据节点的特征维护节点的散列。这使得 (D) 更快但 (B) 更慢(因为当等价类合并时必须更新哈希) 将节点串在一起形成一个循环链表。 (A) 很快,(B) 会很快,但是事实上,将循环列表的一部分与自身“合并”实际上会拆分列表 (C) 会很快,(D) 需要遍历树 与上面类似,但在每个节点中都有一个额外的“向上”指针,可用于查找循环列表的规范成员。

我错过了一个甜蜜的选择吗?

【问题讨论】:

标签应该是算法,而不是算法。 【参考方案1】:

您似乎有两种形式的等价处理。普通等价 (A),被跟踪为保持最新的等价类和结构等价 (D),您偶尔会为此构建单个等价类,然后将其丢弃。

在我看来,如果您为普通和结构等价维护等价类,那么问题在概念上会更简单。如果这为结构等价引入了过多的流失,您可以为结构等价的某些方面维护等价类。然后,您可以找到一个平衡点,您可以负担这些等价类的维护费用,但在构建结构上等价的节点列表时仍然大大减少要检查的节点数量。

【讨论】:

“结构等价”更像是一个索引,以便于发现新的匹配项(例如,如果我知道 A:x = sqrt(z+a+7) 和 B:y = sqrt(z+b+7) 然后学习 C:a=b 它有助于发现我可以合并 A 和 B)。但是您的建议是有道理的(例如,通过***运算符对它们进行索引)。【参考方案2】:

我认为任何一种结构都无法解决您的问题,但您可以看看Disjoint-set data structure。毕竟,等价类与集合的划分是一回事。它应该能够快速处理其中一些操作。

【讨论】:

链接中列出的解决方案基本上是我上面列出的解决方案的一个子集(除了树展平的小例外,我认为这是上指针案例的隐含部分)。你的回答是“不,你没有错过任何甜蜜的选择”吗?【参考方案3】:

退一步说,我建议完全不要使用树。上次我不得不面对类似的问题时,我从一棵树开始,但后来又转向了一个数组。

原因很多,但首要的原因是性能,我的类有多达 100 个左右的孩子,实际上在将它们作为数组操作时比通过树的节点操作时性能更好,主要是因为硬件局部性和 CPU 预取逻辑和 CPU 流水线。

因此,尽管从算法上讲,数组结构需要比树更多的操作 N,但执行这几十个操作可能比在内存中追逐指针要快。

【讨论】:

是的,“树”最终可能会被存储为 TAC 数组或类似的数组。但就整体算法的本质而言,我认为局部性存在风险。

以上是关于在树的节点上构建等价类的好数据结构是啥?的主要内容,如果未能解决你的问题,请参考以下文章

迭代时如何知道我在树的末尾?

迭代时如何知道我在树的末尾?

2021-08-05:监控二叉树。给定一个二叉树,我们在树的节点上安装摄像头。节点上的每个摄影头都可以监视其父对象自身及其直接

2021-08-05:监控二叉树。给定一个二叉树,我们在树的节点上安装摄像头。节点上的每个摄影头都可以监视其父对象自身及其直接子对象。计算监控树的所有节点所需的最小摄像头数量。

树的浅析与实现

构建 ArrayList 树 - Java