Пример #1
0
        /// <summary>
        /// This is the recursive version of Tarjan's strongly connected component algorithm
        /// this is useful for reference and for testing whether the iterative version is correct
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="index"></param>
        /// <param name="n"></param>
        /// <param name="infoMap"></param>
        /// <param name="stack"></param>
        /// <param name="sccs"></param>
        /// <param name="getFanouts"></param>
        private static void StronglyConnect <T>(ref int index, T n, Dictionary <T, SccInfo> infoMap, Stack <T> stack, List <List <T> > sccs, Func <T, IEnumerable <T> > getFanouts)
        {
            // preprocess - on first visit
            stack.Push(n);
            var info = new SccInfo(index: index, lowLink: index, onStack: true);

            infoMap[n] = info;
            index++;

            foreach (var next in getFanouts(n))
            {
                SccInfo nextInfo;
                if (!infoMap.TryGetValue(next, out nextInfo))
                {
                    // next has not been visited: recurse into it
                    StronglyConnect(ref index, next, infoMap, stack, sccs, getFanouts);
                    info.LowLink = Math.Min(info.LowLink, infoMap[next].LowLink);
                }
                else if (nextInfo.OnStack)
                {
                    // next is still on stack and hence in the current SCC
                    info.LowLink = Math.Min(info.LowLink, nextInfo.Index);
                }
            }
            // post process - after all children have been processed
            if (info.Index == info.LowLink)
            {
                // n is still a root node, pop the stack and generate an SCC
                var cycle = new List <T>();
                T   next;
                do
                {
                    next = stack.Pop();
                    infoMap[next].OnStack = false;
                    cycle.Add(next);
                }while (((object)next) != ((object)n));

                sccs.Add(cycle);
            }
        }
Пример #2
0
        /// <summary>
        /// Iterative implementation for finding StronglyConnectedComponent
        /// This implements a recursion stack of activation records to get around stack overflow
        /// in each iteration in the while loop, the current activation record on top of stack "todo"
        /// is examined, and processed according to activation record's current state. it progressed in
        /// sequence:
        ///     - first visit, if first child is not visited yet, push first child, set waitingForChild to true,
        ///                    else, incr activation record
        ///     - if waitingForChild, process child's result, incr activation record
        ///       else, if child is not visited yet, push child, set waitingForChild to true
        ///             else, incr activation record
        ///     ...
        ///     - after processing the last child (or if there is no children at all), IsFinalVisit is true, then
        ///       do the post processing, and pop the activation record
        /// </summary>
        /// <typeparam name="T">data type for node</typeparam>
        /// <param name="index">current index for Tarjan's algorithm</param>
        /// <param name="node">node to visit</param>
        /// <param name="infoMap">dictionary to keep track of node's info for Tarjan algoritm</param>
        /// <param name="stack">stack of nodes in Tarjan's algorithm</param>
        /// <param name="sccs">list of strongly connected components found</param>
        /// <param name="getFanouts">function to find fanouts of nodes in the graph</param>
        private static void StronglyConnectIterative <T>(ref int index, T node, Dictionary <T, SccInfo> infoMap, Stack <T> stack, List <List <T> > sccs, Func <T, IEnumerable <T> > getFanouts)
        {
            var todo = new Stack <ActivationRecord <T> >();

            // activation records belong to stack todo: every entry in todo has one activation record
            // created on push, removed on pop
            todo.Push(AllocateActivationRecord(node, getFanouts));

            while (todo.Any())
            {
                SccInfo info;
                var     currState = todo.Peek();
                var     curr      = currState.Node;

                if (currState.IsFirstVisit())
                {
                    // preprocess - on first visit
                    stack.Push(curr);
                    info          = new SccInfo(index: index, lowLink: index, onStack: true);
                    infoMap[curr] = info;
                    index++;
                }
                else
                {
                    info = infoMap[curr];
                }

                T child;
                if (currState.TryGetChild(out child))
                {
                    if (currState.WaitingForChild)
                    {
                        // returned from recursing into child previously
                        info.LowLink = Math.Min(info.LowLink, infoMap[child].LowLink);
                        // done with child
                        currState.WaitingForChild = false;
                        currState.MoveToNextChild();
                    }
                    else
                    {
                        // first processing of child
                        SccInfo childInfo;
                        if (!infoMap.TryGetValue(child, out childInfo))
                        {
                            //// child has not been visited: recurse into it
                            //// StronglyConnect(ref index, next, infoMap, stack, sccs);
                            //// info.LowLink = Math.Min(info.LowLink, nextInfo.LowLink);
                            currState.WaitingForChild = true;
                            todo.Push(AllocateActivationRecord(child, getFanouts));
                        }
                        else
                        {
                            if (childInfo.OnStack)
                            {
                                // next is still on stack and hence in the current SCC
                                info.LowLink = Math.Min(info.LowLink, childInfo.Index);
                            }
                            currState.MoveToNextChild();
                        }
                    }
                }

                // allows post processing once the last child is processed
                if (currState.IsLastVisit())
                {
                    // all children have been processed : do post processing in recursion
                    if (info.Index == info.LowLink)
                    {
                        // n is still a root node, pop the stack and generate an SCC
                        var cycle = new List <T>();
                        T   next;
                        do
                        {
                            next = stack.Pop();
                            infoMap[next].OnStack = false;
                            cycle.Add(next);
                        }while (((object)next) != ((object)curr));

                        sccs.Add(cycle);
                    }
                    todo.Pop();
                }
            }
        }