Example #1
0
 /// <summary>
 /// Copies a tree structure. (useful in copying a tree structure to a tree view).
 /// </summary>
 /// <typeparam name="A">The node type of the tree to copy.</typeparam>
 /// <typeparam name="B">The destination node type.</typeparam>
 /// /// <param name="getSubNodes"> Get the sub-nodes of any given node.</param>
 /// <param name="newNode">To create a simple non-recursive copy of a node.</param>
 /// <param name="addSubNodes"></param>
 /// <param name="checkType"> Type of circular reference checking to perform.</param>
 /// <returns></returns>
 public static B RebuildTree <A, B>(A srcNode,
                                    Func <A, IEnumerable <A> > getSubNodes,
                                    Func <A, B> newNode,
                                    Action <B, IEnumerable <B> > addSubNodes,
                                    CircularRefernceBehaviour checkType = CircularRefernceBehaviour.DontCheck)
     where A : class
     where B : class
 {
     return(RebuildTree(srcNode, getSubNodes, newNode, addSubNodes, P => true, checkType));
 }
Example #2
0
        /// <summary>
        /// Copies a tree structure. (useful in copying a tree structure to a tree view).
        /// </summary>
        /// <typeparam name="A">The node type of the tree to copy.</typeparam>
        /// <typeparam name="B">The destination node type.</typeparam>
        /// /// <param name="getSubNodes"> Get the sub-nodes of any given node.</param>
        /// <param name="newNode">To create a simple non-recursive copy of a node.</param>
        /// <param name="addSubNodes"></param>
        /// <param name="where"></param>
        /// <param name="checkType"> Type of circular reference checking to perform.</param>
        /// <returns></returns>
        public static B RebuildTree <A, B>(A srcNode,
                                           Func <A, IEnumerable <A> > getSubNodes,
                                           Func <A, B> newNode,
                                           Action <B, IEnumerable <B> > addSubNodes,
                                           Predicate <A> where,
                                           CircularRefernceBehaviour checkType = CircularRefernceBehaviour.DontCheck)
            where A : class
            where B : class
        {
            LinkedList <Tuple <A, B> > list = new LinkedList <Tuple <A, B> >();
            HashSet <A> visited             = new HashSet <A>();
            B           newRootNode         = null;

            list.AddLast(new Tuple <A, B>(srcNode, null));
            while (list.Count > 0)
            {
                var tuple  = list.Pop();
                A   item   = tuple.Item1;
                B   parent = tuple.Item2;

                if (visitOk(item, visited, checkType))
                {
                    if (where (item))
                    {
                        B newItem = newNode(item);
                        if (newRootNode == null) //root node
                        {
                            newRootNode = newItem;
                        }

                        safeAddSubNode(parent, newItem, addSubNodes);

                        list.AddLastAll(getSubNodesSafe(item, getSubNodes).Reverse().Select(N => new Tuple <A, B>(N, newItem)));
                    }
                }
            }

            //done
            return(newRootNode);
        }
Example #3
0
        private static bool visitOk <T>(T item, HashSet <T> visited, CircularRefernceBehaviour checkType)
        {
            if (checkType != CircularRefernceBehaviour.DontCheck)
            {
                if (visited.Contains(item))
                {
                    // error
                    if (checkType == CircularRefernceBehaviour.ThrowException)
                    {
                        throw NodeTraversalException.VisitedTwice(item);
                    }
                    return(false); //indicate it's not ok to visit (ie skip)
                }

                //no error
                visited.Add(item);
                return(true);
            }

            //no check
            return(true);
        }
Example #4
0
        /// <summary>
        /// Enumerates any Tree/graph in a non-recursive manor.
        /// Does not check for circularReferences.
        /// </summary>
        /// <param name="node">Root node.</param>
        /// <param name="getSubNodes"> Get the sub-nodes of any given node.</param>
        /// <param name="order">The visit order.</param>
        /// <param name="checkType">If circular references should be checked, and how to handle them.
        /// Note (1): Checks repeated node, which is not nesesiarly a circular reference (but all circulare references have a repeated node).
        /// Note (2): performance hit reduced if  node generates a good hashcode.
        /// </param>
        public static IEnumerable <T> EnumerateNodes <T>(T node,
                                                         Func <T, IEnumerable <T> > getSubNodes,
                                                         NodeVisitOrder order = NodeVisitOrder.DepthFirstPreOrder,
                                                         CircularRefernceBehaviour checkType = CircularRefernceBehaviour.DontCheck)
            where T : class
        {
            if (node != null) //assuming null indicats an empty tree
            {
                //this acts as a stack or queue to resolve the recursion
                LinkedList <T> list    = new LinkedList <T>();
                HashSet <T>    visited = new HashSet <T>();

                switch (order)
                {
                case NodeVisitOrder.DepthFirstPreOrder:
                    list.AddLast(node);
                    while (list.Count > 0)
                    {
                        T item = list.Pop();
                        if (visitOk(item, visited, checkType))
                        {
                            yield return(item);

                            list.AddLastAll(getSubNodesSafe(item, getSubNodes).Reverse());
                        }
                    }
                    break;

                case NodeVisitOrder.DepthFirstPostOrder:
                    //This has a side effects, the first iteeration is slow (also memory consuming)
                    //as the entire structure is copied into a stack
                    Stack <T> output = new Stack <T>();
                    list.AddLast(node);
                    while (list.Count > 0)
                    {
                        T item = list.Pop();
                        if (visitOk(item, visited, checkType))
                        {
                            output.Push(item);
                            list.AddLastAll(getSubNodesSafe(item, getSubNodes));
                        }
                    }
                    foreach (T item in output)
                    {
                        yield return(item);
                    }
                    break;

                case NodeVisitOrder.BredthFirst:
                    list.AddLast(node);
                    while (list.Count > 0)
                    {
                        T item = list.Dequeue();
                        if (visitOk(item, visited, checkType))
                        {
                            yield return(item);

                            list.AddLastAll(getSubNodesSafe(item, getSubNodes));
                        }
                    }
                    break;
                }
            }
        }