有向图和拓扑排序Java实现
package practice; import java.util.ArrayDeque;
import java.util.Iterator;
import java.util.Stack; public class TestMain {
public static void main(String[] args) {
Digraph a = new Digraph(13);
a.addEdge(0, 1);a.addEdge(0, 5);/*a.addEdge(2, 3);*/a.addEdge(2, 0);a.addEdge(3, 2);
/*a.addEdge(3, 5);*/a.addEdge(4, 3);/*a.addEdge(4, 2);*/a.addEdge(5, 4);a.addEdge(6, 0);
a.addEdge(6, 4);a.addEdge(6, 9);a.addEdge(7, 6);/*a.addEdge(7, 8);*/a.addEdge(8, 7);
a.addEdge(8, 9);a.addEdge(9, 10);a.addEdge(9, 11);a.addEdge(10, 12);a.addEdge(11, 4);
a.addEdge(11, 12);/*a.addEdge(12, 9);*/ System.out.println(a); DirectedDFS dfsa = new DirectedDFS(a);
//第一种方法检查环
System.out.println(dfsa.hasCycle());
System.out.println(); Digraph b = new Digraph(13);
b.addEdge(0, 1);b.addEdge(0, 5);b.addEdge(2, 3);b.addEdge(2, 0);b.addEdge(3, 5);
b.addEdge(5, 4);b.addEdge(6, 4);b.addEdge(6, 9);b.addEdge(7, 6);b.addEdge(8, 7);
b.addEdge(9, 10);b.addEdge(9, 11);b.addEdge(9, 12);b.addEdge(11, 12);b.addEdge(0, 6); DirectedDFS dfsb = new DirectedDFS(b);
//第一种方法检查环
System.out.println(dfsb.hasCycle());
for (Integer integer : dfsb.Topological()) {
System.out.print(integer + " ");
}
}
} /*
* 有向图处理
*/
class DirectedDFS {
private boolean[] marked;
private Digraph G;
private Stack<Integer> cycle;
private int []edgeTo; //轨迹
private boolean[] onStack; //当前搜索轨迹
private Stack<Integer> reversePost; //所有顶点的逆后续排列
/*
* 在图处理类里初始化图
*/
public DirectedDFS(Digraph G) {
marked = new boolean[G.V()];
edgeTo = new int[G.V()];
this.G = G;
DirectedCycle(); //检测环
DepthFirstOrder(); //拓扑排序
} /*
* 深度优先搜索
*/
private void dfs(int s) {
marked[s] = true;
for (int w : G.adj(s)) {
if (!marked[w]) {
edgeTo[w] = s;
dfs(w);
}
}
}
/*
* 广度优先搜索
*/
private void bfs(int s) {
ArrayDeque<Integer> deque = new ArrayDeque<Integer>();
deque.add(s);
marked[s] = true;
int c;
while (!deque.isEmpty()) {
c = deque.poll();
for (int w : G.adj(c)) {
if (!marked[w]) {
marked[w] = true;
edgeTo[w] = c;
deque.add(w);
}
}
}
} /*
* 在G中找到s所有可达的顶点(可以用marked()检测)
*/
public void DFS(int s) {
dfs(s);
}
/*
* 在G中找到source中的所有顶点可到达的所有顶点
*/
public void DFS(Iterable<Integer> sources) {
for (Integer integer : sources) {
dfs(integer);
}
}
/*
* v是可达的吗
*/
public boolean marked(int v) {
return marked[v];
} /*
* 检测s到c的的路径
*/
public void DFDPath(int s, int c) {
for (int i = 0; i < marked.length; i++) {
marked[i] = false;
}
dfs(s);
System.out.print(c + "<-");
while (edgeTo[c] != s) {
c = edgeTo[c];
System.out.print(c + "<-");
}
c = edgeTo[c];
System.out.println(c);
} /*
* 检测s到c的的路径(最短)
*/
public void BFDPath(int s, int c) {
for (int i = 0; i < marked.length; i++) {
marked[i] = false;
}
bfs(s);
System.out.print(c + "<-");
while (edgeTo[c] != s) {
c = edgeTo[c];
System.out.print(c + "<-");
}
c = edgeTo[c];
System.out.println(c);
} /*
* 检测该有向图是否有环
* 要标记当前路径,检查 将要检查到的(并已被标记过的点)是否在当前路径
*/ private void DirectedCycle() {
onStack = new boolean[G.V()];
//先将标记归零
for (int i = 0; i < marked.length; i++) {
marked[i] = false;
}
//挨个搜索节点,标记过的节点就不搜了
for (int i = 0; i < G.V(); i++) {
if (!marked[i]) DirectedCycleDfs(i);
}
} private void DirectedCycleDfs(int s) {
onStack[s] = true; //onStack[v] = true 说明将v加入当前路径
marked[s] = true;
for (int w : G.adj(s)) {
if (this.hasCycle()) return;
else if (!marked[w]) {
edgeTo[w] = s;
DirectedCycleDfs(w);
}
else if (onStack[w]) {
//将这条路径保存到cycle
cycle = new Stack<Integer>();
for (int x = s; x != w; x = edgeTo[x])
cycle.push(x); cycle.push(w);
cycle.push(s);
}
}
onStack[s] = false; //将要切换到另一条路径,将v从当前路径剔除
}
//有环返回true无环返回false
public boolean hasCycle() { return cycle != null;}
//返回找到的环
public Iterable<Integer> cycle() { return cycle;} /*
* 排出顶点的深度优先次序的深度优先搜索
* 拓扑排序 即被指向的一定在指向的后面
*/
public void DepthFirstOrder() {
reversePost = new Stack<Integer>();
for (int i = 0; i < marked.length; i++) {
marked[i] = false;
}
for (int i = 0; i < G.V(); i++) {
if (!marked[i]) dfo(i);
}
}
private void dfo(int s) {
marked[s] = true;
for (int w : G.adj(s)) {
if (!marked[w]) {
dfo(w);
}
}
reversePost.push(s); //可以保证被指向的肯定比指向的先进入栈,所以可以拓扑排序
}
/*
* 拓扑排序
*/
public Iterable<Integer> Topological() {
if (hasCycle()) { return null;} //有环则不能拓扑排序
return reversePost;
}
} /*
* 有向图
*/
class Digraph {
private Bag<Integer>[] digraph;
private int V; //点数
private int E; //边数
public Digraph(int V) {
this.V = V;
digraph = (Bag<Integer>[]) new Bag[V];
for (int i = 0; i < V; i++) {
digraph[i] = new Bag<Integer>();
}
} public int V() { return V;}
public int E() { return E;} public void addEdge(int v, int w) {
digraph[v].add(w);
E++;
} public Iterable<Integer> adj(int V) {
return digraph[V];
} public Digraph reverse() {
Digraph result = new Digraph(V);
for (int i = 0; i < V; i++) {
for (Integer integer : digraph[i]) {
result.addEdge(i, integer);
}
}
return result;
} public String toString() {
String s = V + " vertices, " + E + " edges\n";
for (int v = 0; v < V; v++) {
s += v + ": ";
for (Integer integer : this.adj(v)) {
s += integer + " ";
}
s += "\n";
}
return s;
}
} /*
* 背包
*/
class Bag<T> implements Iterable<T> {
Node first; private class Node {
T value;
Node next;
} public void add(T value) {
Node oldfirst = first;
first = new Node();
first.value = value;
first.next = oldfirst;
} @Override
public Iterator<T> iterator() {
return new BagIterator();
} private class BagIterator implements Iterator<T> {
Node node = first; @Override
public boolean hasNext() {
return node != null;
} @Override
public T next() {
T tempt = node.value;
node = node.next;
return tempt;
}
}
}
上面用到的有向图(Digraph b)

有向图和拓扑排序Java实现的更多相关文章
- 有向图的拓扑排序算法JAVA实现
一,问题描述 给定一个有向图G=(V,E),将之进行拓扑排序,如果图有环,则提示异常. 要想实现图的算法,如拓扑排序.最短路径……并运行看输出结果,首先就得构造一个图.由于构造图的方式有很多种,这里假 ...
- 有向图的拓扑排序的理解和简单实现(Java)
如果图中存在环(回路),那么该图不存在拓扑排序,在这里我们讨论的都是无环的有向图. 什么是拓扑排序 一个例子 对于一部电影的制作过程,我们可以看成是一个项目工程.所有的工程都可以分为若干个" ...
- C++编程练习(12)----“有向图的拓扑排序“
设G={V,E}是一个具有 n 个顶点的有向图,V中的顶点序列 v1,v2,......,vn,满足若从顶点 vi 到 vj 有一条路径,则在顶点序列中顶点 vi 必在顶点 vj 之前.则称这样的顶点 ...
- 拓扑排序(topsort)
本文将从以下几个方面介绍拓扑排序: 拓扑排序的定义和前置条件 和离散数学中偏序/全序概念的联系 典型实现算法解的唯一性问题 Kahn算法 基于DFS的算法 实际例子 取材自以下材料: http://e ...
- [ACM_模拟] POJ 1094 Sorting It All Out (拓扑排序+Floyd算法 判断关系是否矛盾或统一)
Description An ascending sorted sequence of distinct values is one in which some form of a less-than ...
- 数据结构之---C语言实现拓扑排序AOV图
//有向图的拓扑排序 //杨鑫 #include <stdio.h> #include <stdlib.h> #include <string.h> #define ...
- python 排序 拓扑排序
在计算机科学领域中,有向图的拓扑排序是其顶点的先行排序,对于每个从顶点u到顶点v的有向边uv,在排序的结果中u都在v之前. 如果图是有向无环图,则拓扑排序是可能的(为什么不说一定呢?) 任何DAG具有 ...
- Wannafly挑战赛22 B 字符路径 ( 拓扑排序+dp )
链接:https://ac.nowcoder.com/acm/contest/160/B 来源:牛客网 题目描述 给一个含n个点m条边的有向无环图(允许重边,点用1到n的整数表示),每条边上有一个字符 ...
- puk2367 拓扑排序
Description The system of Martians' blood relations is confusing enough. Actually, Martians bud when ...
随机推荐
- 存储结构比较vector,list,dequeue,stack(转)
vector适用:对象数量变化少,简单对象,随机访问元素频繁list适用:对象数量变化大,对象复杂,插入和删除频繁最大的区别是,list是双向的,而vector是单向的.因此在实际使用时,如何 ...
- CSS随笔2
1. css中: a:link { /*表示普通的,未被访问的链接状态*/ color: black;} a:visited { /*表示链接被访问过后的状态*/ color: bluev ...
- Jsp运行环境——Tomcat
JSP JSP全名为Java Server Pages,中文名叫java服务器页面,其根本是一个简化的Servlet设计,它[1] 是由Sun Microsystems公司倡导.许多公司参与一起建立的 ...
- ES6学习目录
前面的话 ES6是JavaScript语言的下一代标准,已经在 2015 年 6 月正式发布.它的目标,是使得 JavaScript 语言可以用来编写复杂的大型应用程序,成为企业级开发语言 为什么要学 ...
- git入门(3)git checkout 和git branch分支的创建和删除
在一个项目中,需要多人同时开发,协同coding 要求: 开发时请用开发分支daily/0.0.1, 禁止直接使用master分支开发新建分支 git checkout -b daily/0.0.1 ...
- ABP+AdminLTE+Bootstrap Table权限管理系统第六节--abp控制器扩展及json封装
一,控制器AbpController 说完了Swagger ui 我们再来说一下abp对控制器的处理和json的封装. 首先我们定义一个控制器,在新增控制器的时候,控制器会自动继承自AbpContro ...
- Ubuntu16.04LTS 环境下编译安装Xen
一.编译安装xen4.6过程 操作系统使用ubuntu16.04,通过下载xen4.6的源代码并编译安装来创建xen4.6环境. 一.依赖包的安装 sudo apt-get install gcc m ...
- 完美结合 Redux 与 React-router (react-router不切换页面)
本文可以解答以下问题: 链接 redux 后 react-router 不切换页面 react-router 路由改变页面却不改变 redux 与 react-router 结合使用的方案 简单的问题 ...
- ECC椭圆曲线详解(有具体实例)
前言 ECC英文全称"Ellipse Curve Cryptography" 与传统的基于大质数因子分解困难性的加密方法不同,ECC通过椭圆曲线方程式的性质产生密钥 ECC164位 ...
- IIS 发布之后 您要找的资源已被删除、已更名或暂时不可用。 404.0 解决方法
步骤一: 如图,我发布网站后,在应用程序池中看到默认的.NetFreamork是2.0版本的,我把它改为4.0后 重新浏览网页就正常了. 如果还是不行,那么进行第二步,