【问题标题】:how to find a NodeData in tree of Nodes?如何在节点树中找到 NodeData?
【发布时间】:2012-04-20 15:34:07
【问题描述】:

我有一个如下的节点结构,这个节点有字符串数据和节点列表作为它的子节点。我想在这棵树中搜索一个数据 我写了一个递归函数 FindNode(Node intree,string target)

public class Node
{
   public string Data;
   public List<Node> Children = new List<Node>();
   //some code
   public Node(string r)
   {
        this.Data = r;
   }

   public string getData()
   {
          return this.Data;
   }

   //some code
   public List<Node> getchildren()
   {
         return this.Children;
    }
       //some code
}

target 是我要查找的字符串,intree 是树的开头(ROOT) 在while循环之后我有问题在那之后我应该返回什么? 如果写错了怎么写?

public Node FindNode(Node intree,string target)
{
    if(intree.getData()==target)
          return intree;
    else 
    {
         while(intree.getchildren()!=null) 
         {
             foreach(Node n in intree.getchildren())
              {
                   FindNode(n,target);
              }
         }
     }
}

【问题讨论】:

  • 什么在这里不起作用?已经很好了。
  • 虽然我有错误,但并非所有路径都返回一个节点
  • @NeginNicki 您的 Children 属性上有一个初始化程序,因此它永远不会为 null(当然,除非您在某些未发布的代码中将其设置为 null)。结果,您将自己打开一个无限循环。
  • 是的,你是绝对正确的,我也没有在我的代码中设置孩子为空

标签: c# oop


【解决方案1】:

使用这个:

public Node FindNode(Node intree,string target)
{
    if(intree.getData()==target)
          return intree;
    else 
    {

              foreach(Node n in intree.getchildren())
              {                
                  Node node = FindNode(n,target) ; //CHECK FOR RETURN 

                  if(node != null) 
                      return node;            

              }

     }

     return null;
}

不同的是我检查了FindNode方法的返回,如果不是null,则返回结果。

请注意,如果树中存在重复节点(具有相同字符串的节点),它将返回 first 出现。

【讨论】:

  • 如果 intree.getchildren 为 null 会发生什么是否正确?这不会给出异常?
  • @NeginNicki:根据我在提供的代码中看到的类定义,它不能为空。
  • 假设经过intree之后会是一片叶子,它会做什么?
  • @NeginNicki:抱歉,没明白你的意思
  • 一段时间后,函数会沿着树向下移动,因此它将到达节点没有任何子节点的地方,因此列表中没有任何节点可用于 foreach
【解决方案2】:

鉴于树中可能有多个匹配项,您最好返回 IEnumerable&lt;Node&gt;。你也不需要把那些奇怪的get 方法放在那里。最后,您的意思是只搜索叶节点还是要搜索所有节点(else 语句)?

public IEnumerable<Node> FindNode(Node intree,string target)
{
    if(intree.Data ==target)
        yield return intree;

    foreach (var node in intree.Children.SelectMany(c => FindNode(c, target))
        yield return node;
}

如果您想要第一个匹配节点,只需在结果上调用First()。如果您想确保只有一个,请致电Single()

【讨论】:

  • 我想搜索整个树,但如果在搜索之间找到第一个节点然后完成它。所以它有更好的速度。我只需要一个匹配。没有很多匹配
  • 但这就是.First() 将为您做的事情。 LINQ 是惰性的,它会搜索直到找到一个然后停止。但这是一个更好的 API,因为如果您后来决定需要一个 API 来查找所有内容,或者您​​需要确保只有 1 个,那么它会处理它。
  • @hsunain - 不,它涉及所有级别,SelectMany 包括递归到 FindNode。
【解决方案3】:

我建议您返回 null 并应用检查您调用此方法的位置,如果返回 null,则表示未找到节点。代码如下

    public static Node FindNode(Node intree, string target)
    {
        if (intree.getData() == target)
            return intree;

        foreach (Node node in intree.getchildren())
        {
            Node toReturn = FindNode(node, target);
            if (toReturn != null) return toReturn;
        }

        return null;
    }

【讨论】:

  • 为什么 this.FindNode 如果你使用的是 this.FindNode 那么我认为只要输入目标就足够了
  • @NeginNicki 是的,您可以删除它。在这种情况下,您也可以将此方法设为静态
  • @NeginNicki Tigran 的回答和我的回答有什么不同。
  • this.findNode 不在这里,因为当您在其他地方使用它时,您没有使用它,所以这个地方总是一样
  • @NeginNicki 我已经删除了这个。但我也认为该方法应该是静态的。
【解决方案4】:
   public Node FindNodeRecursively(Node parentNode, string keyword)
        {
            if(parentNode.getData() == keyword)
            {
                return parentNode;
            }
            else
            {
                if(parentNode.Children != null)
                {
                    foreach(var node in parentNode.Children)
                    {
                        var temp = FindNodeRecursively(node, keyword);
                        if(temp != null)
                            return temp;
                    }
                }
                return null;
            }
        }

【讨论】:

  • 是的,这个 if 语句比我的 while 语句更好,谢谢
  • 你能告诉我 if 在你的 foreach 中的原因吗?为什么你不简单地调用 Find?
  • 您需要在某个时候实际从该方法返回。最终返回的对 Find() 的方法调用不会导致调用方法返回该查找的结果。
猜你喜欢
  • 2011-03-21
  • 1970-01-01
  • 2020-11-26
  • 2018-09-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-13
  • 1970-01-01
相关资源
最近更新 更多