玩转图论算法(4)图的深度优先遍历(检测无向图的环)【Java实现】

 

 

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。
具体步骤如下:

  1. 从任意顶点出发(假设蓝色),将其相邻顶点染成绿色。
  2. 从该相邻顶点出发,将相邻顶点染成蓝色(即与自身颜色相反)。
  3. 采用DFS进行上述过程的递归调用。
    如果出现已访问过的相邻顶点颜色与自己相同,说明不是二分图。


 

 

 

 


项目推荐:

2000多G的计算机各行业电子资源分享(持续更新)

2020年微信小程序全栈项目之喵喵交友【附课件和源码】

Spring Boot开发小而美的个人博客【附课件和源码】

Java微服务实战296集大型视频-谷粒商城【附代码和课件】

Java开发微服务畅购商城实战【全357集大项目】-附代码和课件

最全最详细数据结构与算法视频-【附课件和源码】

在这里插入图片描述

。。。。。。。。。。。。。end。。。。。。。。。。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值