用于获取节点子节点的递归程序

时间:2014-04-22 10:46:40

标签: c#

我有下表作为示例

PNLId   PNLCode PNLParentId Operator    Sign
0      
49  C   51  +   NULL
50  Z   51  +   NULL
51  Y   107 /   NULL
52  B   107 /   NULL
53  B   108 +   NULL

我希望得到关系父/子,所以我定义了以下类:

class Node { 
    public int Id { get; set; } 
    public int? ParentId { get; set; } 
    public string Operator { get; set; } 
    public string Sign { get; set; } 
    public Node Parent { get; set; } 
    public IList Children { get; set; }

    public Node()
    {
        Children = new List<Node>();
    }

    public override string ToString()
    {
        //return "Node: " + Operator + " " + Id + " " + string.Join(",", Children.Select(x => x.Id));
        return "Node: " + Operator + " " + Id + " "
        + string.Join(",", Children.Select(x => string.Format("({0}, {1})", x.Sign, x.Id)));
    }
}

public void GetChild(Node node, Dictionary<int, Node> map, Dictionary<int, Node> mapf)
{
    foreach (var child in node.Children)
    {
        foreach (var pairf in map)
        {
            if (child.Id == pairf.Value.ParentId)
            {
                child.Operator = pairf.Value.Operator;
                var parent = map[pairf.Value.ParentId.Value];


                child.Children.Add(pairf.Value);
                mapf[child.Id] = map[pairf.Value.Id];
                //rootNodes.Add(pairf.Value);
            }
        }
        GetChild(child,map,mapf);
    }
}

我已成功使用此代码获取根节点

var map = new Dictionary(); var rootNodes = new List();

foreach (DataRow row in dt.Rows)
{
    int id = Convert.ToInt32(row["PNLId"]);
    int? parentId = null;
    if (!row.IsNull("PNLParentId"))
    {
        parentId = Convert.ToInt32(row["PNLParentId"]);
    }
    string op = Convert.ToString(row["Operator"]);
    string sign = Convert.ToString(row["Sign"]);
    map[id] = new Node
    {
        Id = id,
        ParentId = parentId,
        Operator = op,
        Sign = sign

    };
}

var mapf = new Dictionary<int, Node>();
 // get rootnods 
foreach (var pair in map)
{
    if (pair.Value.ParentId.Equals(null))
    {
        mapf[pair.Value.Id] = map[pair.Value.Id];
        rootNodes.Add(pair.Value);

    }
}
// get operator for rootnods 
foreach (var pair in mapf)
{
    foreach (var pairf in map)
    {
        if (pair.Value.Id == pairf.Value.ParentId)
        {
            pair.Value.Operator = pairf.Value.Operator; 
            var parent = map[pairf.Value.ParentId.Value];
            rootNodes.Add(pairf.Value);
            GetChild(rootNodes., map, mapf);
        }
    }
}

我需要先构建节点树。然后从根节点开始从子节点复制操作符。为孩子们提供进步并复制他们孩子的操作员。 例如

[92 Node: / 92 (, 36),(, 37)]
[93 Node: + 93 (, 38),(, 39),(, 40)]
[94 Node: / 94 (, 69),(, 70)]
[95 Node: + 95 (, 81),(, 82)]
[96 Node: + 96 (, 83),(, 84),(, 85),(, 86),(, 87),(, 88),(, 89)]

上面的代码不会返回此结果。我该如何修改它?

1 个答案:

答案 0 :(得分:1)

从头开始:

public IEnumerable<Node> CreateTree(DataTable table)
{
    var nodes = GetNodes(table).ToList();
    var roots = new List<Node>();
    foreach(var node in nodes)
    {
        if(node.ParentId==null)
            roots.Add(node);
        else
        {
            var parent = nodes.Single(n => n.Id == node.ParentId);
            CreateRelationship(parent, node);
        }
    }

    foreach (var root in roots)
    {
        UpdateOperators(root);
    }

    return nodes;
}

private void CreateRelationship(Node parent, Node child)
{
    child.Parent = parent;
    parent.Children.Add(child);
}

private IEnumerable<Node> GetNodes(DataTable table)
{
    return from DataRow row in table.Rows select CreateNode(row);
}

private Node CreateNode(DataRow row)
{
    return new Node
    {
        Id = Convert.ToInt32(row["PNLId"]),
        ParentId = row.IsNull("PNLParentId") ? default(int?) : Convert.ToInt32(row["PNLParentId"]),
        Operator = Convert.ToString(row["Operator"]),
        Sign = Convert.ToString(row["Sign"])
    };
}

private void UpdateOperators(Node parent)
{
    if (!parent.Children.Any())
        return;
    parent.Operator = parent.Children.First().Operator;
    foreach (var child in parent.Children)
    {
        UpdateOperators(child);
    }
}
除了Node方法之外,

GetChild应保留代码中的所有内容。另外,Children应声明为IList<Node>,而不是IList

CreateTree是您的入口点 - 它返回所有节点的IEnumerable,整个树中的所有父/子关系都是正确的。