如何找到给定孩子的父母和父母的父母而无需递归?

时间:2018-11-26 19:02:45

标签: c# tree

我的内存列表非常大,我正在寻找最有效的算法来获取项目列表,并在提供孩子时查找所有父母。

List<Data> elements = new List<Data>
{
    new Data {Id = 1, ParentId = null },
    new Data {Id = 2, ParentId = 1},
    new Data {Id = 3, ParentId = 2},
    new Data {Id = 4, ParentId = 3}
};

var parents =
    elements
        .Where(x => x.ParentId != null)
        .ToDictionary(x => x.Id, x => x.ParentId.Value);

IEnumerable<int> GetParents(int i) =>
    parents.ContainsKey(i)
        ? new[] { parents[i] }.Concat(GetParents(parents[i]))
        : Enumerable.Empty<int>();
var result = GetParents(3); //1,2

这很好,但是效率不高。 如何重写代码,以便不对Execute进行递归调用?

2 个答案:

答案 0 :(得分:2)

非递归解决方案非常简单:

var currentId = i;

while (parents.TryGetValue(currentId, out var parentId))
{
    yield return parentId;
    currentId = parentId;
}

我想念什么吗?

答案 1 :(得分:0)

您知道,在处理大量数据时,任何递归方法都不是一个好的选择。由于使用堆堆栈进行递归调用,经过一段时间后,您将获得StackOverFlowException。因此,正如您所问的那样,我为您的问题提供了一种设计简单的非递归实现。

**在此示例中,由于递归方法将StackOverFlowException的提升幅度更大,因此我仅深入7000层。

**一种非递归方法,包括第一个节点的值为 null 作为ParendId

**非递归的执行时间比递归的要好得多。

    public class Data
    {
        public int Id { get; set; }
        public int? ParentId { get; set; }

    }

    static List<Data> elements = new List<Data>();

    static void Main(string[] args)
    {
        //To fill up the list with huge number if items
        elements.Add(new Data() { Id = 1, ParentId = null });
        Enumerable.Range(2, 1000000).ToList().ForEach(x => elements.Add(new Data { Id = x, ParentId = x - 1 }));

        //Making dictionary as you did it
        var parents =elements.ToDictionary(x => x.Id, x => x.ParentId);


        /*Non-Recursive Approach*/
        IEnumerable<int?> GetNonRecursiveParents(int i)
        {
            List<int?> parentsList = new List<int?>();
            if (parents.ContainsKey(i))
            {
                var parentNode = parents[i];
                do
                {
                    parentsList.Add(parentNode);
                    parentNode = parents[parentNode.Value];                        
                }
                while (parentNode != null);
            }
            return parentsList;
        };
        Stopwatch stopwatch = new Stopwatch();
        stopwatch.Start();
        var r = GetNonRecursiveParents(7000);
        stopwatch.Stop();
        var elapsed1 = stopwatch.Elapsed;// Execution time: 00:00:00.0023625



        //Making dictionary as you did it
        parents = elements.Where(x => x.ParentId != null).ToDictionary(x => x.Id, x => x.ParentId);


        /*Recursive Approach*/
        IEnumerable<int?> GetParents(int i) =>
            parents.ContainsKey(i)
                ? new[] { parents[i] }.Concat(GetParents(parents[i].Value))
                : Enumerable.Empty<int?>();
        stopwatch.Restart();
        var result = GetParents(7000); 
        stopwatch.Stop();
        var elapsed2= stopwatch.Elapsed;// Execution time: 00:00:00.0040636
    }