有向图查找环

有向图查找环

import java.util.Scanner;
import java.util.Stack;


//功能:有向图寻找环,并且找出这个环;
//找出的这个环是第一个能出现的环,并且之此一个环,其他的在有环不进行查找

public class DirectedCycle {
	private boolean onStack[]; // 用来标注递归栈中所有遍历的顶点,目的是找出一个环
	private boolean marked[];// 用来标注顶点是否被遍历过
	private int edgeTo[];// 用来储存顶点v-->顶点w的路径,以edgeTo[w]=v的形式储存
	private Stack<Integer> cycle;// 建立一个栈,进行储存一个环中的顶点

	public DirectedCycle(Digraph G) {
		int V = G.getV() + 1; // 顶点是从1开始的,1-v;
		onStack = new boolean[V];
		marked = new boolean[V];
		edgeTo = new int[V];
		for (int i = 1; i < V; i++) { // 将图中的顶点都进行遍历
			if (!marked[i]) {
				dfs(G, i);
			}
		}
	}

	private void dfs(Digraph g, int v) {
		marked[v] = true;
		onStack[v] = true;
		for (int w : g.adj(v)) { // 依次查找顶点v的邻接点
			if (!marked[w]) { // 如果这个邻接点没有被遍历过(marked[w]==false)
				edgeTo[w] = v; // 储存v-->w的路径
				dfs(g, w); // 递归调用
			}
			if (this.hasCycle()) { // 判断cycle这个栈是否存在,如果存在(存在代表环已经出现,找到环了,目的也就达到了,这个类的功能就是看看图中有没有环,有就找出第一个能被找到的环),就结束这个递归方法
				return;
			}
			if (onStack[w]) { // 如果onStack[w]==true,就是说环出现了(因为w顶点被遍历过onStack[w]才等于true,等到又一次看见w顶点时,只能是有环的情况,因为只有环才能碰到一个顶点两次)
				cycle = new Stack<Integer>(); // 建立一个栈
				for (int x = v; x != w; x = edgeTo[x]) { // 将环中的顶点给了栈
					cycle.push(x);
				}
				cycle.push(w);
				cycle.push(v);
			}
		}
		onStack[v] = false;//这里一定要将onStack[v] 从新赋为false,不然会因为递归的原因再一次执行第三个if语句
	}

	public boolean hasCycle() {    //看看栈cycle存不存在
		return cycle != null;
	}

	public Iterable<Integer> Cycle() {  //返回栈cycle,也就是找出的环
		return cycle;
	}

	public static void main(String[] args) {  //main方法是进行验证的
		Scanner sc = new Scanner(System.in);
		int v = sc.nextInt();
		int e = sc.nextInt();
		Digraph R = new Digraph(v);
		for (int i = 0; i < e; i++) {
			int v1 = sc.nextInt();
			int v2 = sc.nextInt();
			R.addEdge(v1, v2);
		}
		DirectedCycle D = new DirectedCycle(R);
		Stack<Integer> stack = (Stack<Integer>) D.Cycle();
		if (stack != null) {
			System.out.println("这个图中存在一条环,这条环是");
			System.out.print(stack);
		} else {
			System.out.println("图中不存在环");
		}
	}
}


在这里附上有向图的储存类
这里有向图的储存用到了邻接表


import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

//有向图
public class Digraph {
	private int V;
	private int E;
	private List<Integer> adj[];
	public Digraph(int v) {
		this.V = v;
		this.E = 0;
		adj = new List[v+1];
		for (int i = 0; i < adj.length; i++) {
			adj[i] = new ArrayList<Integer>();
		}
	}

	public void addEdge(int v, int w) {
		adj[v].add(w);
		E++;
	}

	public Iterable<Integer> adj(int v) {
		return adj[v];
	}

	public int getV() {
		return V;
	}

	public int getE() {
		return E;
	}

	public Digraph reverse() {  //建立一个返图,图中所有的方向取反
		Digraph R=new Digraph(V);
		for(int v=1;v<V+1;v++) {
			for(int w:adj(v)) {
				R.addEdge(w, v);
			}
		}
		return R;
	}
	public static void main(String[] args) {    //main方法进行测试
		Scanner sc=new Scanner(System.in);
		int v=sc.nextInt();
		int e=sc.nextInt();
		Digraph R=new Digraph(v);
		for(int i=0;i<e;i++) {
			int v1=sc.nextInt();
			int v2=sc.nextInt();
			R.addEdge(v1, v2);
		}
		System.out.println("反向图:");
		Digraph D=R.reverse();
		for(int i=0;i<v+1;i++) {
			System.out.println(i+"-->"+D.adj[i]);
		}
		System.out.println("-----------------------");
		System.out.println("原图:");
		for(int i=0;i<v+1;i++) {
			System.out.println(i+"-->"+R.adj[i]);
		}
		System.out.println("图中边数:"+D.getE());
		System.out.println("图中顶点数:"+R.getV());
	}
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值