图(二)
最小生成的树
图中的所有顶点(V)只用最少数量的边(E)保证它们彼此连通,就组成最小生成的树。
注意,最小生成的树边(E)的数量总比顶点(V)的数量少1,即:E = V - 1 ;
记住,不必关心边的长度,不需要找到最短路径,而是找最少数量的边。(在带权图中会发生改变)
创建最小生成的树的算法与遍历几乎相同,它同样可以基于深度优先遍历或广度优先遍历。下面是基于深度优先遍历的代码:
public void mst(){ vertexArray[0].setVisited(true); stack.push(0); while (!stack.isEmpty()) { int currentVertex = stack.peek(); int v = getAdjUnvisitedVertex(currentVertex); if (v == -1) { stack.pop(); } else { vertexArray[v].setVisited(true); stack.push(v); displayVertex(currentVertex); displayVertex(v); } } for (int j = 0; j < MAX_VERTS; j++) { if (vertexArray[j] != null) { vertexArray[j].setVisited(false); } } }
有向图的拓扑排序
有向图:边有方向,只能沿着边的方向移动。以下是邻接矩阵:
A | B | C | |
A | 0 | 1 | 0 |
B | 0 | 0 | 1 |
C | 0 | 0 | 0 |
如图:
1 表示一条边,行标表示从哪里开始,列标表示到哪里结束。例如图中 A -> B,只有行A到列B的值为1,行B到列A的值为0。
邻接表:
顶点 | 包含邻接顶点的链表 |
A | B |
B | C |
C |
不同于无向图是:B链表中不存在A,C链表中不存在B。
拓扑排序
后继:若有一条边从A指向B,那么B就是A的后继。
环:它是一条路径,路径的起点和终点在同一个顶点。例如:A -> B -> C -> D -> A,但是 A -> B -> C,A -> D 不是环。
步骤
- 找到没有后继的顶点
- 从图中删除这个顶点,在列表的前面插入顶点的标记。
- 重复步骤1、2,直到所有顶点都从图中删除。这时列表显示的顶点顺序就是拓扑排序。
public class Vertex { private char label; public Vertex(char label) { this.label = label; } public char getLabel() { return label; } }
public class Graph { private final int MAX_VERTS; private Vertex[] vertexList; private int[][] adjMat; private int nVerts; private char[] sortedList; public Graph(int verts) { this.MAX_VERTS = verts; vertexList = new Vertex[MAX_VERTS]; sortedList = new char[MAX_VERTS]; adjMat = new int[MAX_VERTS][MAX_VERTS]; nVerts = 0; } public void addVertex(char label) { vertexList[nVerts++] = new Vertex(label); } public void addEdge(int start, int end) { adjMat[start][end] = 1; } public void topo() { int orig_Verts = nVerts; /* * 1、调用noSuccessors()找到任意一个没有后继的顶点。 * 2、将该顶点放入sortedList,并把它从图中删除。 * 3、如果没有这样的顶点,必然出现环。 * */ while (nVerts > 0) { int currentVertex = noSuccessors(); if (currentVertex == -1) { System.out.println("error : cycle ."); return; } sortedList[nVerts - 1] = vertexList[currentVertex].getLabel(); deleteVertex(currentVertex); } System.out.print("sort order : "); for (int i = 0; i < orig_Verts; i++) { System.out.print(sortedList[i]); } System.out.print(" . "); } public int noSuccessors() { boolean isEdge; for (int row = 0; row < nVerts; row++) { isEdge = false; for (int col = 0; col < nVerts; col++) { if (adjMat[row][col] > 0) { isEdge = true; break; } } if (!isEdge) { return row; } } return -1; } public void deleteVertex(int delVert) { if (delVert != nVerts - 1) { for (int j = delVert; j < nVerts - 1; j++) vertexList[j] = vertexList[j + 1]; for (int row = delVert; row < nVerts - 1; row++) moveRowUp(row, nVerts); for (int col = delVert; col < nVerts - 1; col++) moveColLeft(col, nVerts); } nVerts--; } private void moveRowUp(int row, int length) { for (int col = 0; col < length; col++) { adjMat[row][col] = adjMat[row + 1][col]; } } private void moveColLeft(int col, int length) { for (int row = 0; row < length; row++) { adjMat[row][col] = adjMat[row][col + 1]; } } }
图z
有向图的连通性