有向图的拓扑排序的理解和简单实现(Java)
如果图中存在环(回路),那么该图不存在拓扑排序,在这里我们讨论的都是无环的有向图。
什么是拓扑排序
一个例子
对于一部电影的制作过程,我们可以看成是一个项目工程。所有的工程都可以分为若干个"活动"的自工程。在这些活动之间,通常会受到一定的条件约束,如其中某些活动必须在另一些活动完成之后才能开始。比如,电影制作不可能在人员到位进驻场地时,导演还没有找到,也不可能在拍摄过程中,场地都没有。这些听起来就很荒谬。
在一个表示工程的有向图中,用顶点表示活动,用弧表示活动之间的优先关系,这样的有向图为顶点表示活动的网,称为AOV网(Activity On Vertex Network)。
AOV网中的弧表示活动之间存在的某种制约关系。
设G={V, E}是一个具有n个顶点的有向图,V中的顶点序列v1v_1v1,v2v_2v2,…,vnv_nvn满足若从顶点viv_ivi到vjv_jvj有一条路径,则在顶点序列中顶点viv_ivi必在顶点vjv_jvj之前。则我们成这样的顶点序列为一个拓扑序列。
摘自:《大话数据结构》
那么拓扑排序,其实就是对一个有向图构造拓扑序列的过程。构造时有两个结果:
- 如果此网的全部顶点都被输出,说明该网是不存在环的AOV网
- 如果输出的顶点数少了,说明这个网存在环,不是一个AOV网
算法思路
从AOV网中选择一个入度为0的顶点输出,然后删去此顶点,并删除以此顶点为尾的弧。继续重复此步骤,直到输出全部顶点或者AOV网中不存在入度为0的顶点为止。
算法实现
数据结构
由于拓扑排序中,需要删除顶点,那么采用邻接矩阵的方式就不太合适,我们可以使用邻接表,这样会更方便。
在算法运行过程中,始终要查找入度为0的顶点,我们在原来顶点表结构的基础上,增加一个入度域in,表示该顶点入度的数字。
边表节点结构体:
public class EdgeNode {
int adjevex;
int weight;
EdgeNode next;
public EdgeNode(int adjevex, EdgeNode next) {
this.adjevex = adjevex;
this.next = next;
}
}
顶点表节点结构体:
public class VertexNode {
int in;
Object data;
EdgeNode firstedge;
public VertexNode(Object data, int in, EdgeNode firstedge) {
this.data = data;
this.in = in;
this.firstedge = firstedge;
}
}
示例AOV图:

对应的邻接表为:

在算法中,我们还需要使用到一个栈,用来存储处理过程中入度为0的顶点下标,目的是为了避免每次查找时都需要遍历顶点表找有没有入度为0的顶点。
拓扑算法代码实现:
package 拓扑排序;
import java.util.Stack;
public class TopologySort {
static VertexNode[] adjList;
Stack stack = new Stack();
public String ToplogicalSort() {
EdgeNode e;
int k, gettop;
int count = 0;
for (int i = 0; i < adjList.length; i++) {
if(adjList[i].in == 0) {
stack.push(i);
}
}
while(!stack.empty()) {
gettop = (int) stack.pop();
System.out.print(adjList[gettop].data + "->");
count++;
for (e = adjList[gettop].firstedge; e != null; e = e.next) {
k = e.adjevex;
if((--adjList[k].in) == 0) { //将其入度减少一位,目的是将顶点上的弧删除
stack.push(k);
}
}
}
System.out.println();
return count < adjList.length ? (String) "ERROR" : (String) "OK";
}
public static EdgeNode getAdjvex(VertexNode node) {
EdgeNode e = node.firstedge;
while(e != null) {
if(e.next == null) break;
else
e = e.next;
}
return e;
}
public static void main(String[] args) {
int[] ins = {0, 0, 2, 0, 2,3,1,2,2,1,1,2,1,2};
int[][] adjvexs = {
{11, 5, 4},
{8,4,2},
{9, 6, 5},
{13, 2},
{7},
{12, 8},
{5},
{},
{7},
{11, 10},
{13},
{},
{9},
{}
};
adjList = new VertexNode[ins.length];
for (int i = 0; i < ins.length; i++) {
adjList[i] = new VertexNode("V"+i, ins[i],null);
if(adjvexs[i].length > 0) {
for (int j = 0; j < adjvexs[i].length; j++) {
if(adjList[i].firstedge == null)
adjList[i].firstedge = new EdgeNode(adjvexs[i][j], null);
else {
getAdjvex(adjList[i]).next = new EdgeNode(adjvexs[i][j], null);
}
}
}
}
TopologySort t = new TopologySort();
System.out.println(t.ToplogicalSort());
}
}
该算法的时间复杂度为O(n+e)。
有向图的拓扑排序的理解和简单实现(Java)的更多相关文章
- 有向图的拓扑排序算法JAVA实现
一,问题描述 给定一个有向图G=(V,E),将之进行拓扑排序,如果图有环,则提示异常. 要想实现图的算法,如拓扑排序.最短路径……并运行看输出结果,首先就得构造一个图.由于构造图的方式有很多种,这里假 ...
- C++编程练习(12)----“有向图的拓扑排序“
设G={V,E}是一个具有 n 个顶点的有向图,V中的顶点序列 v1,v2,......,vn,满足若从顶点 vi 到 vj 有一条路径,则在顶点序列中顶点 vi 必在顶点 vj 之前.则称这样的顶点 ...
- 有向图和拓扑排序Java实现
package practice; import java.util.ArrayDeque; import java.util.Iterator; import java.util.Stack; pu ...
- poj1094 拓扑排序(出度入度简单使用)
Sorting It All Out Time Limit: 1000MS Memory Limit: 10000K Total Submissions: 37764 Accepted: 13 ...
- 机器学习入门 一、理解机器学习+简单感知机(JAVA实现)
首先先来讲讲闲话 如果让你现在去搞机器学习,你会去吗?不会的话是因为你对这方面不感兴趣,还是因为你觉得这东西太难了,自己肯定学不来?如果你觉的太难了,很好,相信看完这篇文章,你就会有胆量踏入机器学习这 ...
- 桶排序和计数排序的理解实现和比较(Java)
比较和非比较的区别 常见的快速排序.归并排序.堆排序.冒泡排序等属于比较排序.在排序的最终结果里,元素之间的次序依赖于它们之间的比较.每个数都必须和其他数进行比较,才能确定自己的位置.比较排序的优势是 ...
- 拓扑排序(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 ...
- HDU-4857(拓扑排序)
Problem Description 糟糕的事情发生啦,现在大家都忙着逃命.但是逃命的通道很窄,大家只能排成一行. 现在有n个人,从1标号到n.同时有一些奇怪的约束条件,每个都形如:a必须在b之前. ...
随机推荐
- jquery text() html() val()
test text() 返回 test html() 返回 test val() 没值, val() 适用于有value属性的元素, 例如: input
- http://classworlds.codehaus.org/apiusage.html
API Usage The Java API can be used to create new realms and connect realms together through importat ...
- android studio打包apk
转载:http://chenfeicqq.iteye.com/blog/1889160 1)Android Studio菜单Build->Generate Signed APK (2) ...
- loadrunner12-用Chrome如何录制脚本
1.下载Chrome最新版本: 2.打开需要录制的网页,按下F12按钮: 3.在弹出框中,选择Network标签,在该标签下单击红色按钮(开始录制按钮): 4.按下F5刷新页面(不管是否需要录制当前页 ...
- [模板]LIS(最长上升子序列)
转载自:最长上升子序列(LIS)长度的O(nlogn)算法 最长上升子序列nlogn算法 在川大oj上遇到一道题无法用n^2过于是,各种纠结,最后习得nlogn的算法 最长递增子序列,Longest ...
- C++ 类 & 对象-C++ 内联函数-C++ this 指针-C++ 类的静态成员
C++ 内联函数 C++ 内联函数是通常与类一起使用.如果一个函数是内联的,那么在编译时,编译器会把该函数的代码副本放置在每个调用该函数的地方. 对内联函数进行任何修改,都需要重新编译函数的所有客户端 ...
- MSP430 G2553 计时/计数器 Timer_A
MSP430G2553包含了两个16-bit Timer_A计时/计数器.本文简单介绍了Timer_A的功能和寄存器使用,本文及后续的随笔部分参考了"Scientific Instrumen ...
- [Erlang35]Erlang18的time
在Erlang 18中, 我们还是可以使用erlang:now/0 但也已经 deprecated啦,大量使用可能引发瓶颈. The default time warp mode has the sa ...
- 如何在CentOS 7中禁用IPv6
最近,我的一位朋友问我该如何禁用IPv6.在搜索了一番之后,我找到了下面的方案.下面就是在我的CentOS 7 迷你服务器关闭IPv6的方法. 你可以用两个方法做到这个. 方法 1 编辑文件/etc/ ...
- [Oracle]Oracle部分函数
1.nvl(a,b) 若a为null,则b 2.to_char(date,'YY-MM-DD') 按格式将date类型转为字符串 to_date('1999/1/1','YY-MM-DD') 将字符串 ...