Ejemplo n.º 1
0
        /// <summary>
        /// Enumerates a tree using the pre-order traversal method.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child nodes.
        /// </param>
        /// <param name="node">The root node of the tree that is to be traversed.</param>
        /// <param name="excludeSubtreePredicate">
        /// A <see cref="System.Func&lt;T, Int32, Boolean&gt;"/> that determines if the current node
        /// that is being evaluated (and all of its descendants) should be included in the
        /// traversal.  This allows for short-circuiting of the pre-order traversal by excluding
        /// particular subtrees from the traversal.  The first argument is the current node being
        /// evaluated and the second argument is the depth of the current node relative to the
        /// original node that the traversal began on.
        /// </param>
        /// <param name="excludeOption">
        /// Used in conjunction with the <paramref name="excludeSubtreePredicate"/>.  Determines
        /// if the entire subtree should be excluded or just its children.
        /// </param>
        /// <returns>
        /// An <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/> that contains all the
        /// nodes in the tree ordered based on a pre-order traversal.
        /// </returns>
        public static IEnumerable <T> PreOrderTraversal <T>(
            this ITreeWalker <T> walker,
            T node,
            Func <T, int, bool> excludeSubtreePredicate,
            ExcludeOption excludeOption)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            // Create a stack to keep track of the branches being traversed.
            Stack <IEnumerator <T> > enumerators = new Stack <IEnumerator <T> >();

            enumerators.Push(Enumerable.Repeat(node, 1).GetEnumerator());

            // Loop as long as we have an enumerator on the stack.  When we have popped the last
            // one off the stack the traversal is complete.
            while (enumerators.Count > 0)
            {
                if (enumerators.Peek().MoveNext())
                {
                    node = enumerators.Peek().Current;

                    // If the 'excludeSubtreePredicate' is not null and evaluates to true then
                    // yield the current node if 'excludeOption' is set to exclude the children.
                    // Otherwise, do not yield anything.
                    if (excludeSubtreePredicate != null &&
                        excludeSubtreePredicate.Invoke(node, enumerators.Count - 1))
                    {
                        if (excludeOption == ExcludeOption.ExcludeDescendants)
                        {
                            yield return(node);
                        }
                    }
                    else
                    {
                        // Yield the current node then push it and its children onto the
                        // stack.
                        yield return(node);

                        enumerators.Push(walker.GetChildren(node).GetEnumerator());
                    }
                }
                else
                {
                    // Pop the enumerator and dispose of it.
                    enumerators.Pop().Dispose();
                }
            }
        }
 public IEnumerable <T> PreOrderTraversal(
     Func <T, int, bool> excludeSubtreePredicate,
     ExcludeOption excludeOption)
 {
     return
         (this
          .TreeWalker
          .PreOrderTraversal(this.Root, excludeSubtreePredicate, excludeOption));
 }
Ejemplo n.º 3
0
 public IEnumerable <T> LevelOrderTraversal(
     Func <T, int, bool> predicate,
     ExcludeOption excludeOption)
 {
     return
         (this
          .TreeWalker
          .LevelOrderTraversal(this.Root, predicate, excludeOption));
 }
        public void PreOrderTraversal_SingleNode(
            ExcludeOption excludeOption,
            int[] expectedResults)
        {
            // Get a valid tree.
            var tree = Node.Create(0);

            // Get a valid ITreeWalker.
            NodeWalker <int> walker = new NodeWalker <int>();

            // Assert that the correct sequence is returned.
            Assert.Equal(
                expectedResults,
                walker.PreOrderTraversal(tree, (n, i) => n.Value == 0, excludeOption).Select(x => x.Value));
        }
        public void PreOrderTraversal_ShortCircuitRootNode(
            ExcludeOption excludeOption,
            int[] expectedResults)
        {
            // Get a valid tree.
            var tree = TestTreeFactory.GetSimpleTree();

            // Get a valid ITreeWalker.
            NodeWalker <int> walker = new NodeWalker <int>();

            // Assert that the correct sequence is returned.
            Assert.Equal(
                expectedResults,
                walker.PreOrderTraversal(tree, (n, i) => n.Value == 0, excludeOption).Select(x => x.Value));
        }
        public void LevelOrderTraversal_ShortCircuitOddNumbers(
            int[] traversalToStartNode,
            ExcludeOption excludeOption,
            int[] expectedResults)
        {
            // Get a valid tree.
            var tree = TestTreeFactory.GetSimpleTree();

            // Get a valid ITreeWalker.
            NodeWalker <int> walker = new NodeWalker <int>();

            // Get the node to begin traversing from.
            var startNode = tree;

            foreach (int i in traversalToStartNode)
            {
                startNode = startNode[i];
            }

            // Assert that the correct sequence is returned.
            Assert.Equal(
                expectedResults,
                walker.LevelOrderTraversal(startNode, (n, i) => n.Value % 2 == 1, excludeOption).Select(x => x.Value));
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Enumerates a tree using the post-order traversal method.
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the parent and child nodes.
        /// </param>
        /// <param name="node">The root node of the tree that is to be traversed.</param>
        /// <param name="excludeSubtreePredicate">
        /// A <see cref="System.Func&lt;T, Int32, Boolean&gt;"/> that determines if the current node
        /// that is being evaluated (and all of its descendants) should be included in the
        /// traversal.  This allows for short-circuiting of the post-order traversal by excluding
        /// particular subtrees from the traversal.  The first argument is the current node being
        /// evaluated and the second argument is the depth of the current node relative to the
        /// original node that the traversal began on.
        /// </param>
        /// <param name="excludeOption">
        /// Used in conjunction with the <paramref name="excludeSubtreePredicate"/>.  Determines
        /// if the entire subtree should be excluded or just its children.
        /// </param>
        /// <returns>
        /// An <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/> that contains all the
        /// nodes in the tree ordered based on a post-order traversal.
        /// </returns>
        public static IEnumerable <T> PostOrderTraversal <T>(
            this ITreeWalker <T> walker,
            T node,
            Func <T, int, bool> excludeSubtreePredicate,
            ExcludeOption excludeOption)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            // Create a stack to keep track of the branches being traversed.
            Stack <IEnumerator <T> > enumerators = new Stack <IEnumerator <T> >();

            enumerators.Push(Enumerable.Repeat(node, 1).GetEnumerator());

            // Loop as long as we have an enumerator on the stack.  When we have popped the last
            // one off the stack the traversal is complete.
            while (enumerators.Count > 0)
            {
                if (enumerators.Peek().MoveNext())
                {
                    node = enumerators.Peek().Current;

                    // If the 'excludeSubtreePredicate' is not null and evaluates to true then
                    // yield the current node if 'excludeOption' is set to exclude the children.
                    // Otherwise, do not yield anything.
                    if (excludeSubtreePredicate != null && excludeSubtreePredicate.Invoke(node, enumerators.Count - 1))
                    {
                        if (excludeOption == ExcludeOption.ExcludeDescendants)
                        {
                            yield return(node);
                        }
                    }
                    else
                    {
                        // Push the current node's children onto the stack.
                        enumerators.Push(walker.GetChildren(node).GetEnumerator());
                    }
                }
                else
                {
                    // Pop the enumerator and dispose of it.
                    enumerators.Pop().Dispose();

                    // Yield the 'Current' value of the enumerator on the top of the stack.
                    if (enumerators.Count > 0)
                    {
                        yield return(enumerators.Peek().Current);
                    }
                }
            }

            //// If the 'excludeSubtreePredicate' is not null and evaluates to true then return
            //// 'node' or return an empty collection, depending on 'excludeOption'.
            //if (excludeSubtreePredicate != null && excludeSubtreePredicate.Invoke(node, 0))
            //{
            //    if (excludeOption == ExcludeOption.ExcludeDescendants)
            //    {
            //        yield return node;
            //    }
            //    yield break;
            //}
            //else
            //{
            //    // Create stacks to keep track of the branches being traversed.
            //    Stack<IEnumerator<T>> enumerators = new Stack<IEnumerator<T>>();
            //    Stack<T> nodes = new Stack<T>();

            //    // Push the current node and its children onto the stacks.
            //    nodes.Push(node);
            //    enumerators.Push(walker.GetChildren(node).GetEnumerator());

            //    // Loop as long as we have a node on the stack.  When we have popped the last node
            //    // off the stack the traversal is complete.
            //    while (nodes.Count > 0)
            //    {
            //        // Try and move to the current node's next child.
            //        if (enumerators.Peek().MoveNext())
            //        {
            //            // If we successfully moved to the next child then set the current node
            //            // to that child.
            //            node = enumerators.Peek().Current;

            //            // If the 'excludeSubtreePredicate' is not null and evaluates to true then
            //            // return yield the current node if 'excludeOption' is set to exclude the
            //            // children.  Otherwise, do not yield anything.
            //            if (excludeSubtreePredicate != null &&
            //                excludeSubtreePredicate.Invoke(node, nodes.Count))
            //            {
            //                if (excludeOption == ExcludeOption.ExcludeDescendants)
            //                {
            //                    yield return node;
            //                }
            //            }
            //            else
            //            {
            //                // Push the current node and its children onto the stacks.
            //                nodes.Push(node);
            //                enumerators.Push(walker.GetChildren(node).GetEnumerator());
            //            }
            //        }
            //        else
            //        {
            //            // If the current node does not have any more children then pop it off of
            //            // the 'nodes' stack and pop its children enumerator off the 'enumerators'
            //            // stack.
            //            // Yield the node that was popped off the stack.
            //            enumerators.Pop().Dispose();
            //            yield return nodes.Pop();
            //        }
            //    }
            //}
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Enumerates a tree using the level-order traversal method. I.e. it
        /// returns all nodes in the first level relative to the specified node,
        /// followed by all nodes in the second level, etc...
        /// </summary>
        /// <typeparam name="T">The type of elements in the tree.</typeparam>
        /// <param name="walker">
        /// The <see cref="ITreeWalker&lt;T&gt;"/> that knows how to find the
        /// parent and child nodes.
        /// </param>
        /// <param name="node">
        /// The root node of the tree that is to be traversed.
        /// </param>
        /// <param name="excludeSubtreePredicate">
        /// A <see cref="System.Func&lt;T, int, bool&gt;"/> that determines if
        /// the current node that is being evaluated (and all of its descendants)
        /// should be included in the traversal. This allows for short-circuiting
        /// of the level-order traversal by excluding particular subtrees from
        /// the traversal. The first argument is the current node being evaluated
        /// and the second argument is the depth of the current node relative to
        /// the original node that the traversal began on.
        /// </param>
        /// <param name="excludeOption">
        /// Used in conjunction with the <paramref
        /// name="excludeSubtreePredicate"/>. Determines if the entire subtree
        /// should be excluded or just its children.
        /// </param>
        /// <returns>
        /// An <see cref="System.Collections.Generic.IEnumerable&lt;T&gt;"/> that
        /// contains all the nodes in the tree ordered based on a level-order
        /// traversal.
        /// </returns>
        public static IEnumerable <T> LevelOrderTraversal <T>(
            this ITreeWalker <T> walker,
            T node,
            Func <T, int, bool> excludeSubtreePredicate,
            ExcludeOption excludeOption)
        {
            // Validate parameters.
            if (walker == null)
            {
                throw new ArgumentNullException("walker");
            }

            if (node == null)
            {
                throw new ArgumentNullException("node");
            }

            // Set the initial depth to 0.
            int depth = 0;

            // Set 'node' as the current level.
            List <IEnumerable <T> > currentLevel = new List <IEnumerable <T> >()
            {
                new T[] { node }
            };
            List <IEnumerable <T> > nextLevel = new List <IEnumerable <T> >();

            // Track whether the current level has any nodes. This is true
            // initially since the current level is simply the node that was
            // passed to this function.
            bool currentLevelHasNodes = true;

            // Enumerate 'currentLevel' and yield each node while adding that
            // node's children to 'nextLevel'. When complete: set 'currentLevel'
            // equal to 'nextLevel', increment 'depth' and repeat the process.
            while (currentLevelHasNodes)
            {
                // Set current level has nodes to false when we enter the loop.
                // This will be set to true again if any nodes are concatenated
                // to 'nextLevel'.
                currentLevelHasNodes = false;
                foreach (T currentNode in currentLevel.SelectMany(x => x))
                {
                    // If the 'excludeSubtreePredicate' is not null and evaluates
                    // to true then exlucude this node and all of its
                    // descendants, depending on 'excludeOption', from the
                    // traversal result.
                    if (excludeSubtreePredicate != null && excludeSubtreePredicate.Invoke(currentNode, depth))
                    {
                        if (excludeOption == ExcludeOption.ExcludeDescendants)
                        {
                            yield return(currentNode);
                        }
                    }
                    else
                    {
                        yield return(currentNode);

                        nextLevel.Add(walker.GetChildren(currentNode));
                        currentLevelHasNodes = true;
                    }
                }

                // Swap the lists. I am reusing lists rather than simply creating
                // a new empty list so that there are fewer objects to be garbage
                // collected.
                var temp = currentLevel;
                currentLevel = nextLevel;
                nextLevel    = temp;
                nextLevel.Clear();

                // Increment the depth counter.
                depth++;
            }
        }