【发布时间】: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