如何在这样的树结构中获取父节点

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&lt;T&gt; 派生时,您创建自定义树结构,您可以设计节点类是什么(此处为 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 反对票是你的,不是吗?如果是,并且您无话可说,请删除它。

以上是关于如何在这样的树结构中获取父节点的主要内容,如果未能解决你的问题,请参考以下文章

使用 PHP 丰富的树结构

二叉树的计算

Java - 具有多个节点的树数据结构 - 如何有效地搜索

Swift 树结构、编码和访问节点

从 Angular 6 材质树中的子节点获取父层次结构

如何从 VB.NET 中的 XML 文件构建唯一的树结构