【问题标题】:traverse all leaf nodes in a tree C#遍历树C#中的所有叶节点
【发布时间】:2015-01-11 05:45:31
【问题描述】:

我正在尝试使用队列遍历树中的所有叶节点。 但我无法得到任何输出。

class MyNode<T>
{
    public T Data { get; set; }
    public MyNode<T> Parent { get; set; }
    public List<MyNode<T>> Children = new List<MyNode<T>>();
    public MyNode(T data, MyNode<T> parent)
    {
        Data = data;
        Parent = parent;
    }

    public override string ToString()
    {
        if (Children == null) return Data.ToString();
        return string.Format("{0} {1} ", Data.ToString(), Children.ToString());
    }

}

一个节点可以有任意数量的子节点。这是我写的打印所有叶节点的内容。我什么也得不到,我想只有最后一行 Console.WriteLine("");被处决了,但我不知道为什么。

    public static void PrintSentence(MyNode<string> root)
    {
        if (root == null)   // Return when the tree is empty.
            return;

        Queue<MyNode<string>> nodeQueue = new Queue<MyNode<string>>();
        nodeQueue.Enqueue(root);

        MyNode<string> currentNode = root;

        while (nodeQueue.Count != 0)
        {
            currentNode = nodeQueue.Peek();
            nodeQueue.Dequeue();

            if (currentNode.Children == null)   // Print strings only when the current node is a leaf node.
                Console.Write(currentNode.Data + " ");

            for (int i = 0; i < currentNode.Children.Count(); i++)
                nodeQueue.Enqueue(currentNode.Children[i]);
        }

        Console.WriteLine("");

    }

感谢您的帮助。 树类是这样的,实际上我在任何地方都找不到我的调试窗口...... 我只写了PrintSentence方法,其他的都是别人写的。

class Tree<T>
{
    public MyNode<T> Root { get; set; }
    public Tree(MyNode<T> root) { Root = root; }
    public override string ToString()
    {
        if (Root == null) return "";
        return Root.ToString();
    }
}

【问题讨论】:

  • 您能否提供更多信息——尤其是您的树?此外,当您在调试器中单步执行代码时,执行了哪些代码,哪些未执行?

标签: c# data-structures


【解决方案1】:

你需要替换这一行

if (currentNode.Children == null)

有了这个

if (currentNode.Children.Count == 0)

这将检查列表是否没有元素(没有子元素)。由于您总是初始化您的列表,因此即使它是空的,它也不会一开始就为空。

【讨论】:

  • 我明白了!非常感谢!
  • 请注意,“它永远不会为空”并不是真的,因为 OP 将该列表公开为公共字段,并且可以轻松地将其设置为 null。很好的答案将包括避免此类情况的建议(即,不公开列表,而是为IEnumerable&lt;Node&gt; 添加 r/o 属性以读取子级列表+添加/设置子级的方法)。
【解决方案2】:

单独的节点遍历和遍历动作如下:

我选择了递归,因为树的递归深度通常不是问题,而且队列不需要太多内存。

public static class MyNodeExt<T>
{
   IEnumerable<T> TraverseLeafs<T>(this MyNode<T> node)
   {
       if (node.Children.Count == 0)
           yield return node;
       else
       {
           foreach(var child in root.Children)
           {
               foreach(var subchild in child.TraverseLeafs())
               {
                   yield return subchild;
               }
           } 
       }
   }
}

和单独的遍历动作:

public static void PrintSentence(MyNode<string> root)
{
    foreach(var node in root.TraverseLeafs())
    {
        Console.Write(node .Data + " ");
    }       
}

【讨论】:

  • 如何在 C# (wpf) 中编译?
【解决方案3】:

通用解决方案:

public static class Hierarchy
{
    /// <summary>
    /// Gets the collection of leafs (items that have no children) from a hierarchical collection
    /// </summary>
    /// <typeparam name="T">The collection type</typeparam>
    /// <param name="source">The sourceitem of the collection</param>
    /// <param name="getChildren">A method that returns the children of an item</param>
    /// <returns>The collection of leafs</returns>
    public static IEnumerable<T> GetLeafs<T>(T source, Func<T, IEnumerable<T>> getChildren)
    {
        if (!getChildren(source).Any())
        {
            yield return source;
        }
        else
        {
            foreach (var child in getChildren(source))
            {
                foreach (var subchild in GetLeafs(child, getChildren))
                {
                    yield return subchild;
                }
            }
        }
    }
}

用法:

    var leafs = Hierarchy.GetLeafs(root, (element) => element.Children);

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-01-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-16
    • 1970-01-01
    相关资源
    最近更新 更多