将树结构转换为2D数组

时间:2017-11-30 08:13:55

标签: c# arrays tree

我需要将树型结构转换为2D数组。

我有一个人类:

public class Person
{
    public string Name { get; set; }
    public List<Person> Children { get; } = new List<Person>();
}

这样填充:

var parent = new Person {Name = "Parent"};
var child1 = new Person {Name = "Child 1"};
var grandchild1 = new Person {Name = "Grandchild 1"};
var child2 = new Person {Name = "Child 2"};

parent.Children.Add(child1);
child1.Children.Add(grandchild1);
parent.Children.Add(child2);

例如:

| Parent |         |               |   
|        | Child 1 |               |
|        |         |  Grandchild 1 |
|        | Child 2 |               |

我想将其转换为以下数组:

var expectedArray = new object[,]
{
    {"Parent", null, null},
    {null, "Child 1", null},
    {null, null, "Grandchild 1"},
    {null, "Child 2", null}
};

目前我已经写了几种扩展方法,但它确实非常混乱。这样做的正确方法是什么?优选地,采用简短的方法。

这是我到目前为止所尝试过的,但它确实非常混乱。

public static class PersonExtensions
{
    public static object[,] To2DArray(this Person person)
    {
        var rowIndex = 0;
        var columnIndex = 0;

        var objectArray = new object[person.GetTotalPersonCount(), person.GetMaxDepth()];

        var stack = new Stack<List<Person>.Enumerator>();
        var enumerator = (new List<Person> {person}).GetEnumerator();
        enumerator.MoveNext();

        do
        {
            var currentPerson = enumerator.Current;
            objectArray[rowIndex, columnIndex] = currentPerson.Name;

            rowIndex++;
            if (currentPerson.Children.Any())
            {
                // Depth is increasing
                columnIndex++;
                stack.Push(enumerator);
                enumerator = currentPerson.Children.GetEnumerator();
            }

            // if (!enumerator.MoveNext() && stack.Count > 0)
            while (!enumerator.MoveNext() && stack.Count > 0)
            {
                // Depth is decreasing
                enumerator = stack.Pop();
                columnIndex--;
            }
        }
        while (stack.Count > 0);

        return objectArray;
    }

    public static int GetMaxDepth(this Person entity)
    {
        int maxDepth = 0;

        foreach (var childEntity in entity.Children)
        {
            maxDepth = Math.Max(maxDepth, childEntity.GetMaxDepth());
        }

        return maxDepth + 1;
    }

    public static int GetTotalPersonCount(this Person entity)
    {
        int count = 1;

        foreach (var childEntity in entity.Children)
        {
            count += childEntity.GetTotalPersonCount();
        }

        return count;
    }
}

修改 我已经设法通过用一段时间替换最终的if(深度减少)来使它工作。但它看起来仍然过于复杂。

1 个答案:

答案 0 :(得分:0)

我相信这个问题可以通过两次使用深度优先搜索来解决。 首先,必须在第一遍中确定树的高度。需要知道深度,以便知道结果的每一行中有多少条目。

接下来,在第二遍中,必须生成实际条目,将节点的名称分配给与树中深度相对应的条目。

第一步可以通过使用Linq将其作为Person类的扩展方法实现,如下所示。

public static int Depth(this Person iPerson)
{
    if (iPerson.Children == null || iPerson.Children.Count() == 0)
    {
        return 1;
    }
    else
    {
        return 1 + Children.Max( iChild => iChild.Depth() );
    }
}

第二步可以实现如下,其中iRoot是树的根。

public static void DepthFirst(int Depth,
                              int CurrentDepth,
                              Person iRoot,
                              List<string>[] Result)
{
    string[] NewEntry = new string[Depth];
    NewEntry[CurrentDepth] = iPerson.Name;
    Result.Add(NewEntry);
    foreach(var iChild in iPerson.Children)
    {
        DepthFirst(Depth, CurrentDepth + 1, iChild, Result);
    }
}

int Depth = iRoot.Depth();
var Result = new List<string[]>();
DepthFirst(Depth, 0, iRoot, Result).