java用广度优先的方法来判断有向图是否有环

这里的代码参考了很多别人的代码和文章。。

今天师兄做笔试题,我也跟着看,碰到了一个要构建有向图并判断节点是否有环的题。



另一位师兄说这个题可以用并查集做,并且做出来了,我用并查集试了试做不出来。。

我觉得这题大概是要用有向图做,考察有向图的构建及寻找有向环


但是我只会对着书本抄代码构建有向图,不会寻找环,就尝试了一下用前不久做爬虫用到的广度遍历来寻找有向环。。


import java.util.*;

public class test
{
	public static void main(String[] args)
	{
		UF uf = new UF();
		
		//构建有向图
		uf.AddDependency(1, 2);
		uf.AddDependency(2, 4);
		uf.AddDependency(4, 1);
		uf.AddDependency(1, 6);
		uf.AddDependency(6, 5);
		uf.AddDependency(5, 7);
		uf.AddDependency(4, 7);
		
		boolean isCycle;
		
		isCycle = uf.MouldelsCycularDependency(7);	//判断对应节点是否有环
				
		System.out.println(isCycle);
	}
}

class UF
{
	final int N = 10;	//节点个数
	//private static int E;
	static Stack<Integer>[] adj;
	
	public UF()	//创建一个N个节点但没有边的图
	{
		adj = (Stack<Integer>[]) new Stack[N];
		for(int n = 0; n < N;n++)
		{
			adj[n] = new Stack<Integer>();
		}
	}
	
	public static void addEdge(int v,int w)	//加边,v朝向w
	{
		adj[v].add(w);
	}
	
	public static Stack<Integer> adj(int v)
	{
		return adj[v];
	}
	
	public void clear()	
	{
		adj = (Stack<Integer>[]) new Stack[N];
		for(int n = 0; n < N;n++)
		{
			adj[n] = new Stack<Integer>();
		}
	}
	
	public static void AddDependency(int Moduleld, int DependModuleld)	//往图里加边
	{
		int v = Moduleld;
		int w = DependModuleld;
		
		addEdge(v,w);
	}
	 
	public static boolean MouldelsCycularDependency(int Moduleld)	//判断是否有环
	{
		int v = Moduleld;
		
		HashMap<Integer,Boolean> oldMap = new HashMap<Integer,Boolean>();
		
		for(int i: adj(v))
		{
			oldMap.put(i, false);
		}		
		
		oldMap = reDo(oldMap,v);
		
		if(oldMap.containsKey(v))
		{

			return true;
		}

		return false;
	}
	
	/**
	 * 广度优先遍历。递归,但是当N过大会StackOverFlow
	 * @param oldMap
	 * @param v 判断的节点
	 * @return
	 */
	public static HashMap<Integer,Boolean> reDo(HashMap<Integer,Boolean> oldMap,int v)	
	{
		//定义newMap
		HashMap<Integer,Boolean> newMap = new HashMap<Integer,Boolean>();
		
		for(Map.Entry<Integer, Boolean> k : oldMap.entrySet())
		{
			if(k.getValue() == false)
			{
				for(int i: adj(k.getKey()))
				{
					if(i == v)
					{
						oldMap.put(i, false);
						return oldMap;
					}
					if(!oldMap.containsKey(i))
					{
						newMap.put(i, false);
					}
				}	
				oldMap.replace(k.getKey(),false, true);
			}
		}
		
		//有新节点,继续遍历
		if (!newMap.isEmpty())
		{
			oldMap.putAll(newMap);
			oldMap.putAll(reDo(oldMap,v)); 
		}
		return oldMap;
	}	
}

有一个致命的缺点,题给的节点数目超多,上面代码进行递归的时候八成会StackOverflow。。


但还是很有成就感的,思考了一晚上至少把最基本功能实现了。。

猜你喜欢

转载自blog.csdn.net/sinat_15901371/article/details/77281363
今日推荐