C# 中的这个树实现有什么问题

本文关键字:实现 什么 问题 | 更新日期: 2023-09-27 18:32:29

我目前正在尝试在 C# 中实现一个非常简单的树/节点类,其中节点有一个对象作为数据,它们可以有零到多个子级。不过,我目前有两个问题:

  1. 出于某种原因,打印出对象最终会打印 TYPE的对象,而不是每个不是的节点的 toString((根。
  2. 我似乎无法正确打印出树的多个分支,并且找不到问题,无论是我的打印问题方法或我向节点添加子节点的方式。

我的节点类如下。

namespace Tree
{
    class Node
    {
        public object data;
        private LinkedList<Node> children;
        public Node(object data)
        {
            this.data = data;
            children = new LinkedList<Node>();
        }
        public void Add(params object[] objects)
        {
            foreach (object obj in objects)
            {
                children.AddLast(new Node(obj));
            }
        }
        public int Count()
        {
            int count = 1;
            foreach (Node n in children)
            {
                count += n.Count();
            }
            return count;
        }
        public void Print(int depth)
        {
            string s = new string(''t',depth);
            s += data;
            Console.WriteLine(s);
            depth++;
            foreach (Node n in children)
            {
                n.Print(depth);
            }
        }
    }
}

为了测试,我正在创建一棵根有三颗子项的树,然后这三个子项中的每一个都有另外三个子项,如下所示。

Node core = new Node("root");
Node o1 = new Node("1");
Node o2 = new Node("2");
Node o3 = new Node("3");
o1.Add(new Node("11"), new Node("12"), new Node("13"));
o2.Add(new Node("21"), new Node("22"), new Node("23"));
o3.Add(new Node("31"), new Node("32"), new Node("33"));
core.Add(o1, o2, o3);
Console.WriteLine(core.Count());
core.Print(0);

预期输出当然是:

13
root
 1
  11
  12
  13
 2
  21
  22
  23
 3
  31
  32
  33

不幸的是,我得到:

4
root
    Tree.Node
    Tree.Node
    Tree.Node

这是我第一次用 C# 做递归,所以也许我缺少一些简单的东西。如果是这种情况,我宁愿解释问题,而不是在代码中给我的解决方案。谢谢。

C# 中的这个树实现有什么问题

快速修复:

public void Add(params Node[] objects)
{
    foreach (Node obj in objects)
    {
        children.AddLast(obj);
    }
}

如果您的Add方法应该添加子节点,那么首先您应该为objects参数使用相应的类型。其次,您应该删除对Node的其他对象转换,因为您已经传递了Node类型参数。

问题出在 Add(( 方法上。目前,它被实现为接收对象并使用这些对象添加节点。但是您正在使用它来添加子节点。您将需要两种不同的方法:

public void AddObjects(params object[] objects)
{
    foreach (object obj in objects)
    {
        children.AddLast(new Node(obj));
    }
}
public void AddChildNodes(params Node[] nodes)
{
    foreach (Node node in nodes)
    {
        children.AddLast(node);
    }
}

然后在设置树结构的地方,使用 AddChildNodes(( 而不是 Add((

这是安装代码的外观:

Node core = new Node("root");
Node o1 = new Node("1");
Node o2 = new Node("2");
Node o3 = new Node("3");
o1.AddObjects("11", "12", "13");
o2.AddObjects("21", "22", "23");
o3.AddObjects("31", "32", "33");
core.AddChildNodes(o1, o2, o3);
Console.WriteLine(core.Count());
core.Print(0);
public Node(object data)
{
    this.data = data;
    children = new LinkedList<Node>();
}

在这里,当您执行类似 Add(new Node("11")) 的操作时,您将此节点的data初始化为类型 Node 的对象。从本质上讲,您构建的节点现在包含另一个节点作为数据,而不是您最初想要的"11"。

不要将object用于任何事情,应该没有理由将其作为 C# 学习的一部分,它只会咬你,就像你在这里发现的那样。对类型使用泛型或标记联合来获取可以包含不同类型的数据的节点。

了解泛型然后重新审视你的树实现,这是我的建议。

除了现有的答案之外,不要将字符串与+=连接:

s += data;

s = String.Concat(s, data.ToString()); 

相反。

另外,data真的需要是对象类型吗?在不了解整个系统的情况下,这只是一个猜测,但拥有一个通用Node类可能是可行的,例如:

class Node<T> 
{
  public T data;
  ...
  public void AddChild(Node<T> childNode) ...
  public void AddChilds(IEnumerable<Node<T>> childNode) ...
}

Node<String> root = new Node<String>("root");
root.AddChild(new Node<String>("FirstBelowRoot");

这不是直接回答你的问题,只是关于如何构建你的类的建议。

试试这个:

public class Node<T> : LinkedList<Node<T>>
{
    public T Data { get; set; }
    public Node(T data)
    {
        this.Data = data;
    }
}

就是这样。好吧,至少对于您的核心代码来说就是这样。您需要这组扩展方法来使用它:

public static class NodeEx
{
    public static void Add<T>(this Node<T> tree, Node<T> child)
    {
        tree.AddLast(child);
    }
    public static int Count<T>(this Node<T> tree)
    {
        int count = 1;
        foreach (Node<T> n in tree)
        {
            count += n.Count();
        }
        return count;
    }
    public static void Print<T>(this Node<T> tree, int depth)
    {
        Console.WriteLine(new string(''t', depth) + tree.Data);
        foreach (Node<T> n in tree)
        {
            n.Print(depth + 1);
        }
    }
}

现在,使用 void Add<T>(this Node<T> tree, Node<T> child) 扩展方法,您可以编写以下代码:

Node<string> core = new Node<string>("root")
{
    new Node<string>("1")
    {
        new Node<string>("11"),
        new Node<string>("12"),
        new Node<string>("13")
    },
    new Node<string>("2")
    {
        new Node<string>("21"),
        new Node<string>("22"),
        new Node<string>("23")
    },
    new Node<string>("3")
    {
        new Node<string>("31"),
        new Node<string>("32"),
        new Node<string>("33")
    },
};

int Count<T>(this Node<T> tree)void Print<T>(this Node<T> tree, int depth)按预期工作。此代码:

Console.WriteLine(core.Count());
core.Print(0);

。生产:

13
root
  1
    11
    12
    13
  2
    21
    22
    23
  3
    31
    32
33

现在,最大的优点是所有可用于LinkedList<T>对象的常规方法都适用于Node<T>