前注:
图算法的Java编程体现了类的思想。首先构造一个基础图类Graph,然后再将每个用于图的算法单独建类,并且这些方法类采用的是预处理思想,即通过方法类构造器函数,一次性就对某一个图对象进行预处理,然后保证每次对该图对象的方法调用都是常数级别的。
Graph类的数据结构主要采用的是链表数组的形式(包结构)和邻接矩阵的形式,对于稀疏图用前者,稠密图用后者。
1. 无向图
图的主要操作就是寻找特殊路径,要满足这一操作,主要采用的是利用搜索方法建立搜索树。无向图的搜索方法有两个深度优先搜索DFS和广度优先搜索BFS。这两类搜索方法用于不同的情况。
1.1. 深度优先搜索
核心思想是:一搜到底,不撞南墙不回头。走不通了就返回上一个节点,直到最后返回起始节点。由于采用了迭代的思想,所以算法其实就是一个隐式的FILO栈结构。
基于该搜索可以判定任意两点间是否相连。并且该搜索也是后期各种算法的基础搜索方式。
1.2. 广度优先搜索
核心思想是:利用一个FIFO队列,将每一个节点的所有相邻节点都加进去,每次吐出一个节点,并把该节点的相邻节点都加进队列去。
基于该搜索,可以较为方便的找到无向图的最短路径。
1.3. 连通分量
通过对所有的点按顺序使用搜索,可以保证得到一棵或者多棵搜索树(森林),并通过连通分量加以区分。
在该小节里,涉及了无环图的判断和二分图的判断算法。
二分图的典型应用就是两类事物构成的图,如电影和演员,航班和机场。
1.4. 符号图
利用了符号表和图的结合,将符号表映射到图序号以完成图的搭建。
注意:在符号图中,不仅要建立符号表映射,还要建立反向映射,因为要对图中具体数据进行读取的时候就要用到反向映射,在这里可以考虑数组结构。
在该小节提到了度数的查询,其思想是结合了BFS和符号二分图。
2. 有向图
有向图区别于无向图的一个地方就是顶点的修改,在无向图的邻接链表中,一条边会存在于两个顶点的链表中,而在有向图中只会出现一次。
在有向图中还会涉及到的一个函数是reverse(),该函数会返回一个反向图,这在后面的算法中会不时用到。比如寻找一个节点的所有父节点,就可以取反得到。reverse()方法的思想很简单,新建一个图对象,利用添加边方法addEdge(),原来是add(v,w):v->w,现在就是addEdge(w,v):w->v。
2.1. 可达性问题
单点可达性:同无向图,可以用DFS和BFS来构建s点和其他点的可达性;
多点可达性:建一个数组all[],对每个点都按照s点的方法进行就可以了。
顶点对的可达性:对all[v].marked[w]调用,即可查询v->w的可达性。注意,该方法的时空损耗都是平方级别的。