4-9 无向图的环检测
如果在遍历的过程中,发现某个顶点有一条边指向已经访问过的顶点,且这个已访问过的顶点不是当前顶点的父节点(这里的父节点表示DFS遍历顺序中的父节点),则说明图包含环。
如图中:从0开始DFS(深度优先遍历),0->6->4->5,此时顶点5的一条边指向顶点0,顶点0已经访问过,但却不是顶点5的父节点(顶点4),说明出现了环。
package graphDFS;
import java.util.ArrayList;
// 无向图的环的检测问题
public class CycleDetection {
// 创建一个数组,
private ArrayList<Integer> res = new ArrayList<>(); // 输出最后深度优先遍历的结果
private boolean[] visited;
private boolean hasCycle = false;
private Graph graph;
public CycleDetection(Graph graph) {
this.graph = graph;
visited = new boolean[graph.V()]; // 结点的数量
//dfs(0);
// 改进的地方:对每一个结点进行遍历
for (int v = 0; v < graph.V(); v++) {
if (!visited[v]) {
dfs(v, v);
}
}
}
private void dfs(int v, int parent) {
visited[v] = true;
res.add(v);
for (int w: graph.adj(v)) { // 遍历该节点的相邻结点
if (! visited[w])
dfs(w, v); // w 的 遍历的上一个结点是 v
else if(w != parent) { // 如果 w 已经被访问了,且不是 v 的上一个结点
hasCycle = true;
}
}
}
public boolean hasCycle(){
return hasCycle;
}
public static void main(String[] args) {
Graph graph = new Graph("g3.txt");
CycleDetection cycleDetection = new CycleDetection(graph);
System.out.println(cycleDetection.hasCycle());
Graph graph2 = new Graph("g4.txt");
CycleDetection cycleDetection2 = new CycleDetection(graph2); // 无环的无向图
System.out.println(cycleDetection2.hasCycle());
}
}
优化:不需要遍历全部的结点,如果判断有环的话,直接return ,退出遍历
package graphDFS;
import java.util.ArrayList;
// 无向图的环的检测问题
public class CycleDetection {
// 创建一个数组,
private ArrayList<Integer> res = new ArrayList<>(); // 输出最后深度优先遍历的结果
private boolean[] visited;
private boolean hasCycle = false;
private Graph graph;
public CycleDetection(Graph graph) {
this.graph = graph;
visited = new boolean[graph.V()]; // 结点的数量
//dfs(0);
// 改进的地方:对每一个结点进行遍历
for (int v = 0; v < graph.V(); v++) {
if (!visited[v]) {
if(dfs(v, v))
hasCycle = true;
break;
}
}
}
// 判断是否有环
private boolean dfs(int v, int parent) {
visited[v] = true;
res.add(v);
for (int w: graph.adj(v)) { // 遍历该节点的相邻结点
if (! visited[w]) {
if (dfs(w, v)) return true; // w 的 遍历的上一个结点是 v
}
else if(w != parent) // 如果 w 已经被访问了,且不是 v 的上一个结点
return true;
}
return false;
}
public boolean hasCycle(){
return hasCycle;
}
public static void main(String[] args) {
Graph graph = new Graph("g3.txt");
CycleDetection cycleDetection = new CycleDetection(graph);
System.out.println(cycleDetection.hasCycle());
Graph graph2 = new Graph("g4.txt");
CycleDetection cycleDetection2 = new CycleDetection(graph2); // 无环的无向图
System.out.println(cycleDetection2.hasCycle());
}
}
4-10 二分图检测
二分图(Bipartite Graph,又称为二部图),是图论中的一种特殊模型。
设G=(V,E)是一个无向图,如果顶点V可分割为两个互不相交的子集{U}、{V},并且图中的每条边(i,j)所关联的两个顶点i和j分别属于这两个不同的顶点集i∈ U,j∈ V,则称图G为一个二分图。
肉眼很难区分出两部分,需要采用一定的算法才可区分,下面就介绍检测的方法–染色.
首先,选择一个节点,置为蓝色(绿色也可),再将与之连线的节点置为对立的颜色-绿色,按深度优先(广度优先也可)的逻辑,将节点依次置为对立色,如果最终结果为:每条边都连接这一个蓝色和一个绿色节点,则二分图检测成功.
4-11 实现二分图检测
二分图中所有顶点分属两个不同集合,U和V。所以,如果一个图是二分图,那对于任意顶点∈U,与它相邻的顶点肯定属于另一个集合V。
具体步骤如下:
- 从任意顶点出发(假设蓝色),将其相邻顶点染成绿色。
- 从该相邻顶点出发,将相邻顶点染成蓝色(即与自身颜色相反)。
- 采用DFS进行上述过程的递归调用。
如果出现已访问过的相邻顶点颜色与自己相同,说明不是二分图。
项目推荐:
Java微服务实战296集大型视频-谷粒商城【附代码和课件】
Java开发微服务畅购商城实战【全357集大项目】-附代码和课件
。。。。。。。。。。。。。end。。。。。。。。。。。。。