遍历C#中树的所有叶节点

4

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

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();
    }
}

请问您能否提供更多信息,特别是关于您的树结构?另外,在调试器中逐步执行代码时,哪些代码被执行,哪些代码未被执行? - Alexei Levenkov
3个回答

3

你需要替换这行代码

if (currentNode.Children == null)

为以下代码

if (currentNode.Children.Count == 0)

这将检查列表是否没有元素(没有子节点)。由于您始终初始化列表,因此即使为空,它也不会为null。


我明白了!非常感谢你! - Ahaha
2
请注意,“它永远不会为空”并不完全正确,因为 OP 将该列表公开为公共字段,很容易将其设置为 null。优秀的答案应包括建议避免这种情况(例如,不要公开 List,而是添加只读属性以读取子节点列表 + 添加/设置子节点的方法)。 - Alexei Levenkov

1
万能解决方案:
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);

0

像这样分离节点遍历和遍历操作:

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

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)中如何编译? - Alan Wayne

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接