using System; using System.Collections.Generic; namespace Chernobyl.Collections.Generic.Hierarchy { /// /// An enumerator that enumerates through a tree in breadth first order /// (http://en.wikipedia.org/wiki/Breadth_first_search). This enumerator /// does not operate on a specific "tree type", instead, it operates on /// types that are structured like tree nodes, i.e. the class holds instances /// of it's own type; for example: /// /// class Foobar /// { /// public List{Foobar} Children { get; } /// } /// /// /// The type that contains a list of instances of it's /// own type (a class that acts as a node in a tree). public class BreadthFirstEnumerator : TreeEnumerator { /// /// Initializes a new instance of the class. /// /// The inclusive node to start from (it will /// become the first value of . /// The method that retrieves the /// from an instance of type /// . Typically, it will look something like /// this (using a lambda expression): /// /// foobar => foobar.Children.GetEnumerator(); /// /// public BreadthFirstEnumerator(T startingNode, Func> getChildEnumerator) : base(startingNode, getChildEnumerator) { } /// /// Advances the enumerator to the next element of the collection. /// /// /// true if the enumerator was successfully advanced to the next element; /// false if the enumerator has passed the end of the collection. /// /// The collection was /// modified after the enumerator was created. public override bool MoveNext() { bool result = true; if (Started == false) { Started = true; Current = Start; EnumeratorLevels.AddLast(GetChildEnumerator(Current)); } else { bool finished = false; while (finished == false) { // have we gone through the entire tree? if (EnumeratorLevels.Count == 0) { finished = true; result = false; } else if (EnumeratorLevels.First.Value.MoveNext() == true) { // grab the new Current and add it's children to our queue Current = EnumeratorLevels.First.Value.Current; EnumeratorLevels.AddLast(GetChildEnumerator(Current)); finished = true; } else { // we are finished with this level, we can move to the next // enumerator over or we can continue to the next level down, // whichever is next EnumeratorLevels.RemoveFirst(); } } } return result; } } }