问题描述
用邻接表表示无向图,并求无向图的连通分量数
输入
结点的数据,边的数据:包括这条边的数据如权值,邻接点域,指向下一条边的指针
输出
邻接表,连通分量的个数
存储结构
邻接表
算法的基本思想
用邻接表来表示图,图的构造方法中有两个参数,第一个为一维数组,包含结点的数据;第二个为二维数组,一共n行3列,行表示边数,前两列为边的相邻两个顶点,最后一列为边的权值等信息。构造过程经过一个双层for循环,第一层遍历结点,第二层遍历边的信息,判断边的相邻两个顶点是否与顶点集中的某个元素相等,相等则添加到该顶点的后面。求连通分量,此处没有通过一个新的数组记录某个点是否被访问,而是为结点类添加一个属性标明其是否被访问,先将所有的结点标记为未被访问,然后遍历每个结点,若结点未被访问,则将结点调用dfs深度遍历方法(调用过此方法的点都被标记为已访问过),每进行完一次dfs方法,计数器加一,最后返回计数器即为连通分量的个数。
源代码
public class Edge {
int adjVex;
int weight;
Edge next;
}
class Vertex {
int data;
Edge edgeHead;
boolean visited;
}
class Graph {
Vertex[] vertices;
int location(int[] vexs,int data){ //求adjvex (即邻接点的下标)
for (int i = 0;i < vexs.length;i++){
if (vexs[i] == data){
return i;
}
}
return -1;
}
public Graph(int[] vexs,int[][] edges) {
//edges是一个n×3的数组,边的权值等于edges[i][2],edges[i][0]指向edges[i][1]
vertices = new Vertex[vexs.length];
for (int i = 0; i < vexs.length; i++) {
vertices[i] = new Vertex();
vertices[i].data = vexs[i];
Edge cur = null;
for (int[] edge : edges) {
if (edge[0] == vexs[i]) {
if (vertices[i].edgeHead == null) {
vertices[i].edgeHead = new Edge();
vertices[i].edgeHead.adjVex = location(vexs,edge[1]);
vertices[i].edgeHead.weight = edge[2];
cur = vertices[i].edgeHead;
} else {
while (cur.next != null) cur = cur.next;
cur.next = new Edge();
cur = cur.next;
cur.adjVex = location(vexs,edge[1]);
cur.weight = edge[2];
}
} else if (edge[1] == vexs[i]) {
if (vertices[i].edgeHead == null) {
vertices[i].edgeHead = new Edge();
vertices[i].edgeHead.adjVex = location(vexs,edge[0]);
vertices[i].edgeHead.weight = edge[2];
cur = vertices[i].edgeHead;
} else {
while (cur.next != null) cur = cur.next;
cur.next = new Edge();
cur = cur.next;
cur.adjVex = location(vexs,edge[0]);
cur.weight = edge[2];
}
}
}
}
}
void dfs(Vertex vertex){
if (!vertex.visited){
vertex.visited = true;
Edge edge = vertex.edgeHead;
while (edge != null){
if (!vertices[edge.adjVex].visited){
dfs(vertices[edge.adjVex]);
}
edge = edge.next;
}
}
}
int countComponent(){
int count = 0;
for (Vertex vertex : vertices) {
vertex.visited = false;
}
for (Vertex vertex : vertices) {
if (!vertex.visited) {
dfs(vertex);
count++;
}
}
return count;
}
void printGraph(){
for (Vertex vertex : vertices) {
Edge e = vertex.edgeHead;
System.out.print(vertex.data);
while(e != null){
System.out.print("--(" +e.weight+")-->"+vertices[e.adjVex].data);
e = e.next;
}
System.out.println();
}
}
}
class Test {
public static void main(String[] args) {
int[] vexs = {1,2,3,4,5,6};
int[][] edges = {{1,2,3},{1,4,5},{2,5,7},{3,6,9},{4,5,9}};
Graph graph = new Graph(vexs,edges);
graph.printGraph();
System.out.println("连通分量的个数\t"+graph.countComponent());
}
}
时间复杂度
关于深度优先的复杂度:DFS算法是一个递归算法,需要借助一个递归工作栈,遍历图的过程实际上是对每个顶点查找其邻接点的过程。当我们使用邻接表存储时,访问顶点为O(V),查找所有的顶点的邻接点的时间为O(E),所以,总的时间复杂度为O(V+E)