图的定义
一个图(graph)G = (V,E) 由 顶点(vertex) 集 V 和 边(edge) 集 E 组成。
每一条边就是一个点对(v,w),其中 v,w∈ V,有时也被称为弧(arc)。
如果点对是有序的,那么图就叫做是有向的(directed),有向的图有时也叫做有向图(digraph)。
顶点 v 和 w 邻接(adjacent) 当且仅当(v,w)∈ E。
有时边还有第三种成分,称作 权(weight) 或 值(cost)。
对于一个顶点 v,边(u,v)的条数称为入度(indegree)。
图中的一条路径(path) 是一个顶点序列 w1,w2,w3,…wN,使得(wi,wi+1)∈ E,1<= i < N。
这样的一条路径的长(length) 是该条路径上的边数,它等于 N - 1。
一条简单路径是这样的一条路径:其上的所有顶点都是互异的但第一个顶点和最后一个顶点可能相同。
有向图中的圈(cycle) 是满足 w1 = wN 且长度至少为 1 的一条路径,如果该条路径是简单路径,那么这个圈就是简单圈。
如果一个有向图没有圈,则称其为无圈的(acyclic)。一个有向无圈图有时也简称为 DAG。
如果一个无向图中从每一个顶点到每一个其他顶点都存在一条路径,则称该无向图是连通的(connected)。
具有这样性质的有向图称为是强连通(strongly connected) 的。
如果边上去掉方向所形成的图是连通的,那么称为基础图(underlying graph)。
如果一个有向图不是连通的,但是它是基础图,那么该有向图称为弱连通(weakly connected) 的。
完全图(complete graph) 是其每一对顶点间都存在一条边的图。
稠密图(dense) :图中 E 的条数接近 V*V 也就是,接近任意两点之间相连。
稀疏图(sparse) :图中 E 的条数远小于 V*V。
图的表示
关于图的具体 Java 实现可以点此查看,或点击下面的链接:
https://github.com/0xZhangKe/Algorithms/tree/master/src/com/zhangke/java/graph/adt
我这里是使用邻接表的方式实现的。
邻接矩阵
表示图的一种简单方法是使用一个二维数组,称为邻接矩阵(adjacency matrix)表示法。
适合稠密的图。
邻接表
如果图是稀疏的,则更好的表示方式是使用邻接表(adjacency list)表示。
拓扑排序
拓扑排序是对有向无圈图的顶点的一种排序,他使得如果存在一条从 vi 到 vj 的路径,那么在排序中 vj 出现在 vi 后面。
一个简单的求拓扑排序的算法是先找出任意一个没有入度的顶点。然后我们显示出该顶点,并将它和它的边一起从图中删除。然后,我们对图的其余部分应用同样的方法处理。
public static <T> void sort(ListDGraph<T> graph) {
Queue<Vertex<T>> queue = new ArrayDeque<>();
Queue<Vertex<T>> resultQueue = new ArrayDeque<>();
int size = graph.size();
int[] indegree = new int[size];//入度数组
for (int i = 0; i < size; i++) {
List<Edge<Vertex<T>>> edges = graph.get(i).getEdgeList();
for (Edge<Vertex<T>> item : edges) {
indegree[graph.get(item.getDest())]++;
}
}
for (int i = 0; i < size; i++) {
if (indegree[i] == 0) {
queue.offer(graph.get(i));
}
}
while (!queue.isEmpty()) {
Vertex<T> vertex = queue.poll();
resultQueue.offer(vertex);
List<Edge<Vertex<T>>> edges = vertex.getEdgeList();
if (edges != null) {
for (Edge<Vertex<T>> edge : edges) {