Javaの隣接行列で表されるランダムグラフがありますが、このグラフ内で連結成分(サブグラフ)を見つけるにはどうすればよいですか?
BFSとDFSを見つけましたが、それらが適切かどうかはわかりません。また、隣接行列にそれらを実装する方法を理解することもできません。
何か案は?
マークを割り当てる必要があります-長さnのint配列。ここで、nはグラフの頂点の数であり、ゼロで埋めます。次に:
1)BFSの場合、以下を実行します。
Components = 0;
Enumerate all vertices, if for vertex number i, marks[i] == 0 then
++Components;
Put this vertex into queue, and
while queue is not empty,
pop vertex v from q
marks[v] = Components;
Put all adjacent vertices with marks equal to zero into queue.
2)DFSの場合、以下を実行します。
Components = 0;
Enumerate all vertices, if for vertex number i, marks[i] == 0 then
++Components;
Call DFS(i, Components), where DFS is
DFS(vertex, Components)
{
marks[vertex] = Components;
Enumerate all vertices adjacent to vertex and
for all vertex j for which marks[j] == 0
call DFS(j, Components);
}
この手順のいずれかを実行した後、コンポーネントには連結成分の数があり、各頂点iについて、marks [i]は連結成分iが属するインデックスを表します。
どちらもO(n)時間、O(n)メモリを使用して完了します。nは行列サイズです。ただし、そうでない限り、BFSをお勧めします。スタックオーバーフローの問題に悩まされることはなく、再帰呼び出しに時間を費やすこともありません。
JavaのBFSコード:
public static boolean[] BFS(boolean[][] adjacencyMatrix, int vertexCount, int givenVertex){
// Result array.
boolean[] mark = new boolean[vertexCount];
Queue<Integer> queue = new LinkedList<Integer>();
queue.add(givenVertex);
mark[givenVertex] = true;
while (!queue.isEmpty())
{
Integer current = queue.remove();
for (int i = 0; i < vertexCount; ++i)
if (adjacencyMatrix[current][i] && !mark[i])
{
mark[i] = true;
queue.add(i);
}
}
return mark;
}
public static void main(String[] args) {
// Given adjacencyMatrix[x][y] if and only if there is a path between x and y.
boolean[][] adjacencyMatrix = new boolean[][]
{
{false,true,false,false,false},
{true,false,false,true,true},
{false,false,false,false,false},
{true,false,false,false,false},
{true,false,false,false,false}
};
// Mark[i] is true if and only if i belongs to the same connected component as givenVertex vertex does.
boolean[] mark = BFS(adjacencyMatrix, 5, 0);
for (int i = 0; i < 5; ++i)
System.out.println(mark[i]);
}
スタックを使用してDFSを繰り返し実装し、再帰呼び出しと呼び出しスタックオーバーフローの問題を排除できます。実装はキューを使用したBFSと非常に似ています。頂点をスタックにプッシュするときではなく、ポップするときに頂点にマークを付ける必要があります。
Scipyのスパースモジュールを使用して、
入力が(label_1,label_2)
からweight
までの辞書であるとすると、次のコードを実行できます。
vertices, edges = dict2graph(cooccur_matrix, Edge_threshold)
n, components = sparse.csgraph.connected_components(edges, directed=False)
print ('Found {n} components'.format(n=n))
components = collect_components(components,vertices)
components = [c for c in components if len(c)>=component_threshold]
print ('removed {k} small components'.format(k=n-len(components)))
print ('component sizes: '+ repr([len(c) for c in components]))
Githubで完全な要点を参照してください ここ