我的内存列表非常大,我正在寻找最有效的算法来获取项目列表,并在提供孩子时查找所有父母。
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进行递归调用?
答案 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
}