为了账号安全,请及时绑定邮箱和手机立即绑定

如何在C#中定义一个可继承的树类来构建由不同类类型组成的树状数据结构?

如何在C#中定义一个可继承的树类来构建由不同类类型组成的树状数据结构?

C#
青春有我 2021-11-21 10:59:21
我一直在阅读这个主题一段时间,但我只是不太了解 C# 语法。希望这对您来说很清楚,并且您愿意帮助我。我发现的例子是相同类型或类的树结构,这不是我在这里需要的。简而言之,我希望能够定义任意类,例如下面的 NodeClassA、NodeClassB、NodeClassC,并且能够将任意数量的这些相互附加以形成如下所示的任意树数据结构。每个节点都应该能够访问其父节点。任何人都可以帮助正确定义下面的 MyTreeClass 吗?NodeClassB__NodeClassC__NodeClassA____NodeClassB____NodeClassB____NodeClassA__NodeClassA____NodeClassC__NodeClassB__NodeClassCclass MyTreeClass{    public void AddChild(T NodeClassX) { }    public T GetChild() { }}class NodeClassA:MyTreeClass{    public void foo(int a) { }}class NodeClassB : MyTreeClass{    public void foo(int b) { }}class NodeClassC : MyTreeClass{    public void foo(int c) { }}
查看完整描述

3 回答

?
RISEBY

TA贡献1856条经验 获得超5个赞

这在严格的类型安全方式中是不可能的,因为类型安全是在编译时确保的,这需要静态声明类型。但是树是在运行时动态构建的,具有不同的节点类型。


要走的路是拥有一个可以是通用的静态节点数据类型。可以从给定的基本数据类型导出不同类型的数据。使用多态来处理它们。即使用具有不同实现的相同方法集。


public class TreeNode<T>

{

    public T Data { get; set; }


    private List<TreeNode<T>> _children = new List<TreeNode<T>>();

    public IEnumerable<TreeNode<T>> Children => _children;


    public TreeNode<T> AddChild(T data)

    {

        var node = new TreeNode<T> { Data = data };

        _children.Add(node);

        return node;

    }


    public void VisitPreOrder(Action<T, int> action, int level)

    {

        action(Data, level);

        foreach (TreeNode<T> node in Children) {

            node.VisitPreOrder(action, level + 1);

        }

    }

}


public class Tree<T>

{

    public TreeNode<T> Root { get; } = new TreeNode<T>();


    public void VisitPreOrder(Action<T, int> action)

    {

        Root.VisitPreOrder(action, 0);

    }

}

现在您可以拥有与树完全无关的数据类:


public class A

{

    public int Index { get; set; }


    public virtual void PrintLine()

    {

        Console.WriteLine($"A {Index}");

    }

}


public class B : A

{

    public override void PrintLine()

    {

        Console.WriteLine($"B {Index}");

    }

}


public class C : B

{

    public override void PrintLine()

    {

        Console.WriteLine($"C {Index}");

    }

}

从您的示例创建树结构


TreeNode<A> node;


var tree = new Tree<A>();

tree.Root.Data = new B { Index = 0 };            // NodeClassB

tree.Root.AddChild(new C { Index = 1 });         // __NodeClassC

node = tree.Root.AddChild(new A { Index = 2 });  // __NodeClassA

node.AddChild(new B { Index = 3 });              // ____NodeClassB

node.AddChild(new B { Index = 4 });              // ____NodeClassB

node.AddChild(new A { Index = 5 });              // ____NodeClassA

node = tree.Root.AddChild(new A { Index = 6 });  // __NodeClassA

node.AddChild(new C { Index = 7 });              // ____NodeClassC

tree.Root.AddChild(new B { Index = 8 });         // __NodeClassB

tree.Root.AddChild(new C { Index = 9 });         // __NodeClassC 

因为每个数据类型(基类型或派生类型)都做适合其类型的事情,所以您不需要知道它的确切类型。这称为多态。这将打印树结构:


tree.VisitPreOrder((item, level) => {

    Console.Write(new string('_', 4 * level));

    item.PrintLine();

});

B 0

____C 1

____A 2 ____B

3 ____B

4

________A 5

____A 6

________C 7

____B 8

____C 9


请注意,T在声明Tree<T>andTreeNode<T>类时,您不需要知道具体的数据类型,因为它T是通用的。你也可以声明


var stringTree = new Tree<string>();

var intTree = new Tree<int>();


查看完整回答
反对 回复 2021-11-21
?
红颜莎娜

TA贡献1842条经验 获得超12个赞

您可能正在寻找复合模式,这是一种对树结构建模的常用方法,例如一个文件系统,其中您有一个叶子(文件)和容器(文件夹),而容器可以包含其他容器或叶子本身。


在您的情况下,至少到目前为止您描述的方式要简单一些,因为这些节点之间没有行为差异。所以对于你的结构,节点实际上可以是浅的,你只需要在你的基类中实现组合。这样,您就没有叶子,而只有(不同的)容器。


public abstract class BaseNode

{

    public IList<BaseNode> Children

    { get; } = new List<BaseNode>();

}


public class NodeClassA : BaseNode { }

public class NodeClassB : BaseNode { }

public class NodeClassC : BaseNode { }

然后你就可以构建你的结构了。


查看完整回答
反对 回复 2021-11-21
?
慕娘9325324

TA贡献1783条经验 获得超4个赞

只需让您的任意类继承或组合某种类型的集合即可。例如,您的任意类都可以是列表。增强将是 add 方法设置子级的父级并且父级是一个属性。


查看完整回答
反对 回复 2021-11-21
  • 3 回答
  • 0 关注
  • 192 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信