有向图和拓扑排序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 ...
随机推荐
- 会话跟踪Cookie与Session
会话跟踪用来跟踪用户的整个会话,常用的是Session和Cookie.Cookie通过客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份. 1.Cookie 1.1概念及使 ...
- python--DenyHttp项目(2)--ACM监考服务器端
服务器端: #coding:utf-8 ''' ServerGui.py 设置比赛开始时间 设置比赛结束时间 若时间无误启动监听服务 ''' import time import re import ...
- Handler案例-简易打地鼠游戏(延时处理消息)
1. 游戏思路 (1)用ImageView显示地鼠,初始状态将ImageView设置为不可见状态.当开始游戏后,通过sendMessageDelayed()方法延时发送消息,使ImageView显示出 ...
- /etc/shadow,/etc/passwd,/etc/shadow,/etc/passwd文件的内容解释
1.1 /etc/passwd文件内容格式 该目录存储的是操作系统用户信息,该文件为所有用户可见 用户名: 密码 : uid : gid :用户描述:主目录:登陆shell 举个 ...
- txt文件怎么设置默认打开是用这个EditPlus软件打开
1.如果是正常安装的Editplus,只需要右击“txt文件”,在“打开方式”中选择“打开程序”,再点击“浏览”,找到“Editplus”打开,再将“始终使用选择的程序打开这种文件”前面的“口”选中, ...
- COM编程_第一讲_深入COM框架以及实现简单的COM
一丶我们要理解COM是什么(为什么理解) 现在很多人会用com(也就是ALT)但是不知道原理,如果改一点东西,那么整体的框架重来,因为你不懂改哪里,如果懂了,那么遇到问题,那么就会知道我要怎么做,是什 ...
- [BZOJ 3629][ JLOI2014 ]聪明的燕姿
这道题考试选择打表,完美爆零.. 算数基本定理: 任何一个大于1的自然数N,都可以唯一分解成有限个质数的乘积N=P₁^a₁ P₂^a₂…Pn^an,这里P₁<P₂<…<Pn均为质数, ...
- 迷宫 洛谷 p1605
题目背景 迷宫 [问题描述] 给定一个N*M方格的迷宫,迷宫里有T处障碍,障碍处不可通过.给定起点坐标和 终点坐标,问: 每个方格最多经过1次,有多少种从起点坐标到终点坐标的方案.在迷宫 中移动有上下 ...
- 备注: ubt 16.04 安装 gtx 1060 --- 成功运行 tensorflow - gpu
---------------------------------------------------------------------------------------------------- ...
- 使用Openfire配置安卓客户端聊天服务器
Openfire是一种即时通信服务器,采用开放的XMPP协议,您可以使用各种支持XMPP协议的IM客户端软件登陆服务. Openfire 采用Java开发,开源的实时协作(RTC)服务器基于XMPP( ...