有向无环图
在图论中,如果一个有向图无法从某个顶点出发经过若干条边回到该点,则这个图是一个有向无环图(DAG图)。
因为有向图中一个点经过两种路线到达另一个点未必形成环,因此有向无环图未必能转化成树,但任何有向树均为有向无环图。
邻接矩阵
邻接矩阵(Adjacency Matrix)是表示顶点之间相邻关系的矩阵。设G=(V,E)是一个图,其中 V= [ v 1 , v 2 , … , v n ] [v_1,v_2,…,v_n] [v1,v2,…,vn] 。G的邻接矩阵是一个具有下列性质的 n n n 阶方阵:
- 对无向图而言,邻接矩阵一定是对称的,而且主对角线一定为零(在此仅讨论无向简单图),副对角线不一定为 0 0 0,有向图则不一定如此。
- 在无向图中,任一顶点 i i i 的度为第 i i i 列(或第 i i i 行)所有非零元素的个数,在有向图中顶点 i i i 的出度为第 i i i 行所有非零元素的个数,而入度为第 i i i 列所有非零元素的个数。
- 用邻接矩阵法表示图共需要 n 2 n^2 n2 个空间,由于无向图的邻接矩阵一定具有对称关系,所以扣除对角线为零外,仅需要存储上三角形或下三角形的数据即可,因此仅需要 n ( n − 1 ) 2 \frac{n(n-1)}{2} 2n(n−1)个空间。
邻接表
邻接表是图的一种最主要存储结构,用来描述图上的每一个点。对图的每个顶点建立一个容器(
n
n
n 个顶点建立
n
n
n 个容器),第
i
i
i 个容器中的结点包含顶点
V
i
V_i
Vi 的所有邻接顶点。实际上我们常用的邻接矩阵就是一种未离散化每个点的边集的邻接表。
在有向图中,描述每个点向别的节点连的边(点
a
→
a\rightarrow
a→点
b
b
b 这种情况)。
在无向图中,描述每个点所有的边(点
a
−
a-
a−点
b
b
b这种情况)
拓扑排序
对一个有向无环图(Directed Acyclic Graph简称DAG) G 进行拓扑排序,是将 G 中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边<
u
,
v
u,v
u,v>
∈
\in
∈ E(G),则
u
u
u 在线性序列中出现在
v
v
v 之前。通常,这样的线性序列称为满足拓扑次序(Topological Order)的序列,简称拓扑序列。简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
public class TopologicalSort {
public static void main(String [] args){
List<Integer>[] g;
int[] ans;
g = generateAdjacencyList(6, new int[][] {{0, 1}, {2, 1}, {2, 5}, {3, 2}, {3, 5}, {5, 0}, {5, 4}});
ans = topologicalSort(g);
System.out.println(Arrays.toString(ans));
}
private static int[] topologicalSort(List<Integer>[] g){
int[] ans, counts;
int i, j, k, n;
Queue<Integer> queue;
n = g.length;
ans = new int[n];
counts = new int[n];
queue = new LinkedList<>();
for(i = 0; i < n; i++){
for(j = 0; j < g[i].size(); j++){
counts[g[i].get(j)]++;
}
}
for(i = 0; i < n; i++){
if(counts[i] == 0){
queue.offer(i);
}
}
k = 0;
while(!queue.isEmpty()){
i = queue.poll();
ans[k++] = i;
for(j = 0; j < g[i].size(); j++){
counts[g[i].get(j)]--;
if(counts[g[i].get(j)] == 0){
queue.offer(g[i].get(j));
}
}
}
return ans;
}
private static List<Integer>[] generateAdjacencyList(int n, int[][] edges){
List<Integer>[] ans;
int i, m;
ans = new List[n];
m = edges.length;
for(i = 0; i < n; i++){
ans[i] = new LinkedList<>();
}
for(i = 0; i < m; i++){
ans[edges[i][0]].add(edges[i][1]);
}
return ans;
}
}