Bugün, keyfi olarak derin bir grafiğe geçmek ve onu tek bir numarada düzleştirmek için bir yöntem uygulayacağım. Bunun yerine, önce küçük bir arama yaptım ve buldum: Bu iyi görünüyor, ancak pratikte bunun (durum doğar gibi) eşdeğer elle yazılmış kod kullanarak daha kötü anlamlı gerçekleştirir buldum TeorideLINQ ile verimli grafik geçişi - yinelenen özyineleme
public static IEnumerable<T> Traverse<T>(this IEnumerable<T> enumerable, Func<T, IEnumerable<T>> recursivePropertySelector)
{
foreach (T item in enumerable)
{
yield return item;
IEnumerable<T> seqRecurse = recursivePropertySelector(item);
if (seqRecurse == null) continue;
foreach (T itemRecurse in Traverse(seqRecurse, recursivePropertySelector))
{
yield return itemRecurse;
}
}
}
Bir grafikten geçmek ve yapılması gerekenleri yapmak. Bunun şundan şüpheleniyorum çünkü bu yöntemde, geri döndürdüğü her öğe için yığının keyfi olarak derin bir seviyeye kadar gevşemesi gerekiyor.
Ayrıca, bu yöntemin ortadan kaldırılması durumunda bu yöntemin çok daha verimli çalışacağından şüpheleniyorum. Aynı zamanda, özyinelemeyi ortadan kaldırmada çok iyi olmayacağım.
Özyinelemeyi gidermek için bu yöntemi yeniden yazmayı bilen var mı?
Yardımlarınız için teşekkür ederiz.
DÜZENLEME: Tüm ayrıntılı yanıtlar için çok teşekkürler. Bir çözümleyici yöntemi kullanmamaya benzeyen Eric'in çözümüne karşı orijinal çözümü kıyaslamaya çalıştım ve bunun yerine bir lambda ve garip bir şekilde tekrarlayan bir şekilde çaprazlama yaptım, lambda özyineleme diğer iki yöntemden çok daha hızlıdır. TraverseOld orijinal yöntemdir
class Node
{
public List<Node> ChildNodes { get; set; }
public Node()
{
ChildNodes = new List<Node>();
}
}
class Foo
{
public static void Main(String[] args)
{
var nodes = new List<Node>();
for(int i = 0; i < 100; i++)
{
var nodeA = new Node();
nodes.Add(nodeA);
for (int j = 0; j < 100; j++)
{
var nodeB = new Node();
nodeA.ChildNodes.Add(nodeB);
for (int k = 0; k < 100; k++)
{
var nodeC = new Node();
nodeB.ChildNodes.Add(nodeC);
for(int l = 0; l < 12; l++)
{
var nodeD = new Node();
nodeC.ChildNodes.Add(nodeD);
}
}
}
}
nodes.TraverseOld(node => node.ChildNodes).ToList();
nodes.TraverseNew(node => node.ChildNodes).ToList();
var watch = Stopwatch.StartNew();
nodes.TraverseOld(node => node.ChildNodes).ToList();
watch.Stop();
var recursiveTraversalTime = watch.ElapsedMilliseconds;
watch.Restart();
nodes.TraverseNew(node => node.ChildNodes).ToList();
watch.Stop();
var noRecursionTraversalTime = watch.ElapsedMilliseconds;
Action<Node> visitNode = null;
visitNode = node =>
{
foreach (var child in node.ChildNodes)
visitNode(child);
};
watch.Restart();
foreach(var node in nodes)
visitNode(node);
watch.Stop();
var lambdaRecursionTime = watch.ElapsedMilliseconds;
}
}
, TraverseNew Eric'in yöntemdir ve açıkçası lamda lambda olduğunu.
Makinemde TraverseOld 10127 ms, TraverseNew 3038 ms alır, lambda özyineleme 1181 ms alır.
Bu tipik olarak, numaralandırma yöntemlerinin (verim dönüşü ile) anında yürütme yerine 3 kat daha uzun sürebilir mi? Yoksa başka bir şey mi oluyor?
, görünüşe her seviyede, yani, saf bir fibonacci gibi f (x) = f (x - 1) + f (x - 2) 'dir. – mellamokb
Son versiyon, ilk ikisiyle aynı miktarda çalışmaya yakın bir yerde değil; özellikle, herhangi bir liste tahsis edilmez, diziden diziye öğelerin kopyalanması vb. Bir nüfus sayımcısı olduğunuzu hayal edin; Evden eve yürümeye ve rahatsız etmeme karar verirseniz, herhangi bir bilgiyi yazın, o zaman işiniz çok daha hızlı olacaktır. –
TraverseOld ve TraverseNew'i 3 yıl sonra nerede bulabilirim? – user1756694