递归树遍历-保存到每个节点的路径

时间:2018-09-25 18:39:50

标签: c# dictionary recursion

我正在尝试创建一个递归函数,该递归函数遍历数字字典,然后输出每个节点的遍历路径。

数据结构看起来像这样:

var tree = new Dictionary<int, List<int>>()
{
    {888, new List<int>() {44}},
    { 44, new List<int>() {183, 275, 100, 216}},
    {100, new List<int>() {299, 400}},
    {299, new List<int>() {504}},
    {216, new List<int>() {33}}
};

所以代表数据结构的树形结构看起来像这样

                 888
                /   \
               44    (many other nodes and subnodes)
           / /  \  \
        183 275 100 216
               /  \    \
              299 400   33
             /
            504

我想返回一个列表列表,输出类似这样的内容

[888, 44, 183]
[888, 44, 275]
[888, 44, 100, 299, 504]
[888, 44, 100, 400]
[888, 44, 216, 33]

到目前为止,这可能是不正确的。我可以成功获得一些想要的结果。我认为问题在于,这并不是在所有子节点都已被访问的情况下删除具有子节点的节点。

public List<int[]> FindPaths(int currentNode, Dictionary<int, List<int>> tree, List<int> temp, List<int> visitedNodes)
    {
            if (tree.ContainsKey(currentNode))
            {
                if (!visitedNodes.Contains(currentNode))
                {
                    visitedNodes.Add(currentNode);
                }

                foreach (var node in tree[currentNode])
                {
                    visitedNodes.Add(node);
                    temp.Add(node);
                    // call method again with new values
                    FindPaths(node, tree, temp, visitedNodes);                                            
                }

                // if node has no children left and is not a leaf node
                // do something here?
            }
            else // we have reached a leaf node
            {
                paths.Add(temp.ToArray());
                temp.RemoveAt(temp.Count - 1);
                return paths;
            }
            return paths;
    }

调用函数

paths = new List<int[]>();
var temp = new List<int>();
var vistedNodes = new List<int>();
var result = FindPaths(888, tree, temp, vistedNodes);

有人可以帮助我获得所需的输出吗?如果可能的话,我想递归地完成这项工作

3 个答案:

答案 0 :(得分:0)

尝试这个:

public List<List<int>> FindPaths(int currentNode, Dictionary<int,List<int>> tree)
{
    List<List<int>> paths = new List<List<int>>();

    if(tree.ContainsKey(currentNode))
    {
        foreach(var node in tree[currentNode])
        {
            var subPaths = FindPaths(node,tree);
            foreach(var subPath in subPaths)
            {
                subPath.Insert(0,currentNode);
                paths.Add(subPath);
            }
        }
    }
    else
    {
        paths.Add(new List<int>(){currentNode});
    }
    return paths;
}

请注意,这是假设您没有圆形路径(A-> B-> C-> A)。如果词典中包含一个,您将陷入循环中。如果可能的话,您必须跟踪访问的节点并避免对其进行重新处理。

答案 1 :(得分:0)

类似于您的方法,此解决方案是在访问时继续添加节点,在该节点不存在任何键时收集列表,并在迭代结束时删除该元素。

void findPaths(int root, Dictionary<int,List<int>> tree,List<List<int>> pathList, List<int> visitedNodes)
{
    visitedNodes.Add(root);
    if(tree.ContainsKey(root))
    {
        foreach(int v in tree[root])
        {
            findPaths(v,tree,pathList,visitedNodes);
            visitedNodes.RemoveAt(visitedNodes.Count - 1);
        }
    }
    else
    {
            pathList.Add(new List<int>(visitedNodes));
    }
}

答案 2 :(得分:0)

使用这种方法很容易解决

//Just some helper method
public static IEnumerable<TKey[]> GetPaths<TKey, TDictImpl>(this IDictionary<TKey, TDictImpl> dict) where TDictImpl : IEnumerable<TKey>
{
    var watchlist = new List<TKey>();
    var outlist = new List<List<TKey>>();
    GetPaths(dict, dict.Keys.First(), watchlist, outlist, new List<TKey> { dict.Keys.First() });
    return outlist.Select((l) => l.ToArray());
}
private static void GetPaths<TKey, TDictImpl>(this IDictionary<TKey, TDictImpl> dict, TKey parent, List<TKey> watchlist, List<List<TKey>> outlist, List<TKey> current) where TDictImpl : IEnumerable<TKey>
{
    //Try to get our child from the dict
    if (!dict.TryGetValue(parent, out TDictImpl subs))
    {
        //No child found, no further navigation needs to be done
        return;
    }
    foreach (var it in subs)
    {
        //Simple check to make sure we do not end in some endless loop
        if (watchlist.Contains(it))
        {
            throw new FormatException($"The key {it.ToString()} was attempted to be traversed a second time in {parent.ToString()}.");
        }
        else
        {
            watchlist.Add(it);
        }
        //Add everything to our outlist
        var tmp = current.Concat(new TKey[] { it }).ToList();
        outlist.Add(tmp);
        //Proceed with possible childnodes
        GetPaths(dict, it, watchlist, outlist, tmp);
    }
}

生成
var tree = new Dictionary<int, List<int>>()
{
    {888, new List<int>() {44}},
    { 44, new List<int>() {183, 275, 100, 216}},
    {100, new List<int>() {299, 400}},
    {299, new List<int>() {504}},
    {216, new List<int>() {33}}
};
var res = Random.GetPaths(tree);

以下输出

[888, 44]
[888, 44, 183]
[888, 44, 275]
[888, 44, 100]
[888, 44, 100, 299]
[888, 44, 100, 299, 504]
[888, 44, 100, 400]
[888, 44, 216]
[888, 44, 216, 33]