【问题标题】:Prevent creating a tree that can have a loop防止创建可能有循环的树
【发布时间】:2021-11-03 09:43:12
【问题描述】:

我正在尝试创建一棵树。这个想法很简单。每个节点都有一个父节点。我希望能够将父节点分配给不会导致树畸形的任何节点(有一个循环)

我想要做的是如下

public class Node
{
    public string ParentNodeId {get;set;}
    public string BreadCrumb {get;set;}
    public bool IsLeaf {get;set;}

    public void AssignToParent(Node ParentNode)
}

我的想法是我将维护一个反映整个父链的 BreadCrumb 字符串,例如,

nodeD 
{
ParentNodeId: "C"
BreadCrumb: "A,B,C"
IsLeaf: true
}

nodeE
{
ParentNodeId: "B"
BreadCrumb: "A,B"
IsLeaf: true
}

我的理解是:在父节点赋值时,只有当前节点(被添加为子节点)在该父节点任意叶子的BreadCrumb内时才会出现循环。

假设我们将 nodeC 指定为 nodeA 的父节点。我们可以检测到叶子 D 有一个包含 A、B、C 的面包屑,这意味着我们不应该将 C 指定为 A 的父节点。

编辑:为了澄清我试图不必遍历整个树,从父级开始查找循环,特别是当/如果我使用可能导致许多数据库访问的 ORM 时,除非我正在写作自定义 SQL 脚本。

*Edit2:我会在这棵树上做的最频繁的操作是:

  • 分配/取消分配一个节点作为当前节点的父节点。
  • 列出一个节点下的所有子节点

树只是一个简单的层次结构,例如属于一个企业集团的多个公司的部门。有时您只想选择一个部门并将其转移到另一家公司,但从不希望一个部门下的开发人员“拥有”整个企业集团。或者想想 Windows 文件夹/注册表结构?

我的问题:这是阻止导致循环而不必总是遍历树的好策略吗?是不是我理解有误?我是不是把事情复杂化了?

【问题讨论】:

  • 根据您的需要,如果我理解正确,只需检查您添加的节点不是父节点的引用,一个简单的循环将遍历树。
  • 谢谢@TheGeneral 我有点担心性能以及如何将该结构放入数据库。从 DB 中为循环一一提取记录可能会很慢。因此,我考虑加载树,通过选择 StartsWith("A") 将其展平,并处理所有内容,因为平面列表很快。但是经过进一步思考,从树中分离一个节点似乎会给我带来麻烦,因为我需要重写所有孩子的所有面包屑
  • SqlServer 有 HierarchyId,它有专门针对这类问题的方法/工具,但是它们在 EF 中的支持很差(如果你正在使用它),所以面包屑的想法可能是你最好的选择。
  • 您不必储存面包屑。这是一个节点的祖先应该遵循的冗余信息。
  • @m.raynal 如果树是通过在每个父级中存储指向子级的链接列表来定义的,那么这将是正确的。但是 OP 正在做相反的事情:在孩子中存储指向父级的链接。

标签: c# algorithm data-structures tree


【解决方案1】:

有些数据结构旨在跟踪不相交的集合。数据结构的目的是能够执行以下两种操作:

  • 检查两个元素是否在同一个集合中
  • 合二为一

特别是我使用的是与union by rank and path compression optimizations 的不相交集森林。虽然听起来很复杂,但实际上很容易实现。

现在如果你有这个结构,你要解决的问题是微不足道的 - 如果你让一个节点 X 成为节点 Y 的父节点,当且仅当 XY 属于同一套。否则你应该合并XY 的集合。

请注意,我提出的解决方案在内存使用方面更高效,速度更快。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-03-15
    • 1970-01-01
    相关资源
    最近更新 更多