/// <summary>
        /// 有向グラフの強連結成分を判定する
        /// </summary>
        /// <param name="graph">グラフ</param>
        /// <returns>ノード→クラスタID配列</returns>
        public static int[] Calc(DirectedAdjacencyList graph)
        {
            var results = Visit(graph);

            int[] cluster_array = AntiVisit(graph, results.invOrderArray);

            return(cluster_array);
        }
        /// <summary>
        /// 正方向の後順探索で各接点に訪問する
        /// </summary>
        /// <param name="graph">グラフ</param>
        /// <returns>ノード→訪問順配列と、訪問順→ノード配列</returns>
        private static (int[] orderArray, int[] invOrderArray) Visit(DirectedAdjacencyList graph)
        {
            // 作業領域を確保
            int[] order_array     = new int[graph.NodeNum];
            int[] inv_order_array = new int[graph.NodeNum];
            for (int i = 0; i < graph.NodeNum; i++)
            {
                order_array[i] = UNVISITED;
            }

            int         order       = 0;
            Stack <int> visit_stack = new Stack <int>(graph.NodeNum);

            for (int i = 0; i < graph.NodeNum; i++)
            {
                // 未訪問のノードから始める
                if (order_array[i] != UNVISITED)
                {
                    continue;
                }
                visit_stack.Clear();

                visit_stack.Push(i);
                order_array[i] = VISITED;
                while (visit_stack.Count != 0)
                {
                    int v = visit_stack.Peak();

                    // vから到達できる未訪問のノードに訪問する
                    bool     move     = false;
                    LinkList edgeList = graph.GetOutLinkedEdgeList(v);
                    for (LinkNode node = edgeList.head; node != null; node = node.next)
                    {
                        int w = GraphUtil.GetOpposite(v, graph.EdgeList[node.data]);
                        if (order_array[w] == UNVISITED)
                        {
                            visit_stack.Push(w);
                            order_array[w] = VISITED;
                            move           = true;
                        }
                    }

                    // どこにも移動できなかったら後順探索に従って番号付け
                    if (!move)
                    {
                        visit_stack.Pop();
                        order_array[v]         = order;
                        inv_order_array[order] = v;
                        order++;
                    }
                }
            }

            return(order_array, inv_order_array);
        }
        /// <summary>
        /// 逆方向の前順探索で各接点に訪問する
        /// </summary>
        /// <param name="graph">グラフ</param>
        /// <param name="invOrderArray">訪問順→ノード配列</param>
        /// <returns>ノード→クラスタID配列</returns>
        public static int[] AntiVisit(DirectedAdjacencyList graph, int[] invOrderArray)
        {
            int[] result = new int[graph.NodeNum];
            for (int i = 0; i < result.Length; i++)
            {
                result[i] = UNVISITED;
            }

            int         cluster_id  = 0;
            Stack <int> visit_stack = new Stack <int>(graph.NodeNum);

            for (int i = 0; i < graph.NodeNum; i++)
            {
                // i番目に大きい訪問順を持つノードから始める
                int s = invOrderArray[(graph.NodeNum - 1) - i];
                // 訪問済みならスキップ
                if (result[s] != UNVISITED)
                {
                    continue;
                }
                visit_stack.Clear();

                visit_stack.Push(s);
                result[s] = cluster_id;
                while (visit_stack.Count != 0)
                {
                    int v = visit_stack.Pop();

                    // 反有向木において、vから到達できる未訪問のノードに訪問する
                    LinkList edgeList = graph.GetInLinkedEdgeList(v);
                    for (LinkNode node = edgeList.head; node != null; node = node.next)
                    {
                        int w = GraphUtil.GetOpposite(v, graph.EdgeList[node.data]);
                        if (result[w] == UNVISITED)
                        {
                            visit_stack.Push(w);
                            result[w] = cluster_id;
                        }
                    }
                }
                cluster_id++;
            }

            return(result);
        }
Example #4
0
        public void BasicTests()
        {
            var adjList = new DirectedAdjacencyList <int>(2);

            adjList.AddVertex(10);
            adjList.AddVertex(20);

            adjList.CreateEdge(10, 20);

            Assert.IsTrue(adjList.Adjacent(10, 20));
            Assert.IsFalse(adjList.Adjacent(20, 10));

            var undirectedList = new UndirectedAdjacenyList <int>(2);

            undirectedList.AddVertex(10);
            undirectedList.AddVertex(20);

            undirectedList.CreateEdge(10, 20);

            Assert.IsTrue(undirectedList.Adjacent(10, 20));
            Assert.IsTrue(undirectedList.Adjacent(20, 10));
        }
        public static AdjacencyList ReadGraph(string filepath)
        {
            StreamReader reader = new StreamReader(filepath);

            int  no_of_node = -1;
            int  no_of_edge = -1;
            bool directed   = false;

            while (!reader.EndOfStream)
            {
                string[] record = reader.ReadLine().Split(' ');

                // 1フィールド目が属性
                switch (record[0])
                {
                case "TYPE":
                    directed = record[2] == "DIRECTED";
                    break;

                case "NO_OF_NODE":
                    no_of_node = int.Parse(record[2]);
                    break;

                case "NO_OF_EDGE":
                    no_of_edge = int.Parse(record[2]);
                    break;

                case "EDGE_CODE_SECTION":
                    goto READ_EDGE_DATA;
                }
            }
            // エッジデータの読み込み
READ_EDGE_DATA:
            if (no_of_node == -1)
            {
                Common.ErrorExit("ノード数の指定がありません。");
            }
            if (no_of_edge == -1)
            {
                Common.ErrorExit("エッジ数の指定がありません。");
            }

            int[][] edge_list = new int[no_of_edge][];
            for (int i = 0; i < no_of_edge; i++)
            {
                if (reader.EndOfStream)
                {
                    Common.ErrorExit("NO_OF_EDGEで指定されたエッジ数よりも少ないデータが記載されています。");
                }
                string[] record = reader.ReadLine().Split(' ');
                edge_list[i]    = new int[2];
                edge_list[i][0] = int.Parse(record[0]);
                edge_list[i][1] = int.Parse(record[1]);
            }

            if (!reader.EndOfStream)
            {
                Common.ErrorExit("NO_OF_EDGEで指定されたエッジ数よりも多いデータが記載されています。");
            }

            AdjacencyList instance;

            if (directed)
            {
                instance = new DirectedAdjacencyList(no_of_node, no_of_edge, edge_list);
            }
            else
            {
                instance = new UndirectedAdjacencyList(no_of_node, no_of_edge, edge_list);
            }
            return(instance);
        }