如何在这样的树结构中获取父节点
Posted
技术标签:
【中文标题】如何在这样的树结构中获取父节点【英文标题】:How to get parent node in a tree structure like this 【发布时间】:2016-04-15 12:51:38 【问题描述】:当树结构是这样的时候,如何获得父节点:
public class TreeModel
public int ID get; set;
public List<TreeModel> Children get; set;
假设我们不能将父元素项添加到此类 (public TreeModel Parent get; set; )。
编辑
如何从m1中获取元素m22(ID=22)父m2(ID=2)?我认为我们可以遍历 m1 并在条件正确时以某种方式返回父级。
var m1 = new TreeModel() ID = 1 ;
var m2 = new TreeModel() ID = 2 ;
var m21 = new TreeModel() ID = 21 ;
var m22 = new TreeModel() ID = 22 ;
var m3 = new TreeModel() ID = 3 ;
m1.Children.Add(m2);
m2.Children.Add(m21);
m2.Children.Add(m22);
m1.Children.Add(m3);
var parent = m1.GetParent(p => p.ID == 22); //<-- How?
【问题讨论】:
为什么需要父母?你如何使用这个结构?如果 TreeModel 没有指向父级的链接,那么您将无法获得父级。您必须添加一种或另一种链接。 【参考方案1】:public IEnumerable<TreeModel> GetAllDescendants(IEnumerable<TreeModel> rootNodes)
var descendants = rootNodes.SelectMany(_ => GetAllDescendants(_.Children));
return rootNodes.Concat(descendants);
public static TreeModel GetParent(this TreeModel rootNode, Func<TreeModel, bool> childSelector)
var allNodes = GetAllDescendants(new [] rootNode );
var parentsOfSelectedChildren = allNodes.Where(node => node.Children.Any(childSelector));
return parentsOfSelectedChildren.Single();
m1.GetParent(_ => _.ID == 22);
-
获取所有节点的平面列表
在此列表中搜索其直接子节点包含 m22 的节点
【讨论】:
【参考方案2】:使用此代码模式。它简化了代码,因为您不必显式地将节点添加到子节点,并且每个节点都知道它的父节点是谁以及它的子节点是谁。而且它是所有类型安全的。
class Program
static void Main(string[] args)
var m1=new TreeModel() ID=1 ;
var m2=new TreeModel(m1) ID=2 ;
var m21=new TreeModel(m2) ID=21 ;
var m22=new TreeModel(m2) ID=22;
var m3=new TreeModel(m1) ID=3 ;
var item=m1.RecursiveFind((p) => p.ID==22);
var parent=item.Parent;
// parent.ID == 2
var root=item.Root;
// root.ID == 1;
public class TreeModel : Tree<TreeModel>
public int ID get; set;
public TreeModel()
public TreeModel(TreeModel parent) : base(parent)
public class Tree<T> where T : Tree<T>
protected Tree() : this(null)
protected Tree(T parent)
Parent=parent;
Children=new List<T>();
if(parent!=null)
parent.Children.Add(this as T);
public T Parent get; set;
public List<T> Children get; set;
public bool IsRoot get return Parent==null;
public T Root get return IsRoot?this as T:Parent.Root;
public T RecursiveFind(Predicate<T> check)
if(check(this as T)) return this as T;
foreach(var item in Children)
var result=item.RecursiveFind(check);
if(result!=null)
return result;
return null;
当您从 Tree<T>
派生时,您创建自定义树结构,您可以设计节点类是什么(此处为 TreeModel
)以及如何在需要时处理父母、孩子和兄弟姐妹。
【讨论】:
【参考方案3】:怎么样:
public class SaneTreeModel: TreeModel
public SaneTreeModel Parent get; set;
【讨论】:
【参考方案4】:我将通过首先找到满足条件的第一个元素(在您的示例中为 ID == 22)然后找到该元素的父元素来解决此问题。不是最好的解决方案,但也许您需要将它们单独用于其他用途。
public TreeModel GetParent(Func<TreeModel, bool> function)
return GetParent(Where(function));
private TreeModel GetParent(TreeModel treeModel)
if (Children == null) return null;
if (Children.Contains(treeModel)) return this;
foreach (TreeModel child in Children)
TreeModel result = child.GetParent(treeModel);
if (result != null)
return result;
return null;
private TreeModel Where(Func<TreeModel, bool> function)
if (Children == null) return null;
foreach (TreeModel child in Children)
if (function(child))
return child;
TreeModel result = child.Where(function);
if (result != null)
return result;
return null;
如果您将此代码块放在您的 TreeModel 类中,您提供的示例将返回 m2
【讨论】:
【参考方案5】:绝对不是,像这样的子节点你不能得到它的父节点。只是因为没有任何引用它。
要获取节点的父节点,您必须添加父字段或将引用保存在其他地方(通过变量或其他东西)。
编辑
@Zulis 如果从根节点搜索,肯定能找到你要的节点。但正如我所说,只有子节点你不能这样做。
但我认为你应该避免搜索,因为那样会很慢
【讨论】:
我不同意 - 在提供的示例中,m22 是 m1 的直接后代,因此他(或她,idk)绝对可以通过递归搜索找到父节点 m2(m1 的直接子节点)跨度> 但是他不能只用子节点来做。查看我的更新了解更多 @ManfredRadlwimmer 反对票是你的,不是吗?如果是,并且您无话可说,请删除它。以上是关于如何在这样的树结构中获取父节点的主要内容,如果未能解决你的问题,请参考以下文章