拓扑排序算法介绍
拓扑排序解决的是一系列相互依赖的事件的排序问题,比如Ant中有很多的Task,而某些Task依赖于另外的Task,编译之前需要清理空间,打包之前要先编译,但其它一些Task处理顺序可以调换(是无所谓前后,不是并行), 如何安排Task的执行顺序就可以用拓扑排序解决。熟悉Java的朋友应该都知道Spring,一个非常优秀的解决组件(Bean)依赖的框架,组件之间可能有依赖关系,也可能没有关系,如何按顺序创建组件也是相同的问题。本文使用的是图搜索算法里面的深度优先排序算法解决问题。需要特别指出的是拓扑排序算法的结果很可能有多个(不依赖的可以调换位置),而算法也可以有多种,深度优先排序算法只是其中一种而已。拓扑排序为线性排序,效率为O(|V|+|E|),其中|V|表示顶点数,|E|表示边的数量。
拓扑排序算法Java实现
图像(Graph)的Java抽象实现
图可以抽象为顶点和边,分为有向图和无向图,拓扑排序里面使用的事有向图(依赖),本文中图的边用相邻链表方法表示。每一个顶点有名字(name),颜色(color, 搜索时候用来标记处理状态),父节点(parent,搜索结束可以得到多棵树),开始处理时间(discover),结束处理时间(finish)。请注意Vertex类override了equals和hash方法。具体代码如下:
深度优先算法
遍历图的顶点,如果当前顶点还没有处理过(color为white),就处理该节点(visitVertex),处理节点的算法(visitVertex)也不难,时间维度加1,当前节点颜色置为gray(开始处理),然后优先处理其子节点(深度优先),结束之后时间维度加1,当前节点颜色置为black(结束处理)。此时就可以把该节点放到目标链表里面了(最终排好序的链表)。由于Java里面Integer值不可变(Immutable),只能选择全局变量或者自己实现时间计数器,本文选择后者(TimeRecorder)。代码如下:
- staticclassTimeRecorder{
- privateinttime=0;
- publicintgetTime(){
- returntime;
- }
- publicvoidsetTime(inttime){
- this.time=time;
- }
- }
- publicstaticVertex[]topologicalSort(Graphgraph){
- Set<Vertex>vertexSet=graph.getVertexSet();
- if(vertexSet.size()<2){
- returnvertexSet.toArray(newVertex[0]);
- }
- LinkedList<Vertex>sortedList=newLinkedList<Vertex>();
- TimeRecorderrecorder=newTimeRecorder();
- for(Vertexvertex:vertexSet){
- if(vertex.color==Color.WHITE){
- visitVertex(graph,vertex,recorder,sortedList);
- }
- }
- returnsortedList.toArray(newVertex[0]);
- }
- publicstaticvoidvisitVertex(Graphgraph,Vertexvertex,
- TimeRecorderrecorder,LinkedList<Vertex>sortedList){
- recorder.time+=1;
- vertex.color=Color.GRAY;
- vertex.discover=recorder.time;
- Map<Vertex,Vertex[]>edgeMap=graph.getAdjacencys();
- Vertex[]adjacencys=edgeMap.get(vertex);
- if(adjacencys!=null&&adjacencys.length>0){
- for(Vertexadjacency:adjacencys){
- if(adjacency.color==Color.WHITE){
- adjacency.parent=vertex;
- visitVertex(graph,adjacency,recorder,sortedList);
- }
- }
- }
- recorder.time+=1;
- vertex.color=Color.BLACK;
- vertex.finish=recorder.time;
- sortedList.addLast(vertex);
- }
构建图以及测试
我们的测试图例如下(箭头的方向表示的是依赖):
为了打印排好序的结果,实现了printVertex函数。测试代码如下:
- publicstaticvoidmain(String[]args){
- Graphgraph=newGraph();
- Set<Vertex>vertexSet=graph.getVertexSet();
- Map<Vertex,Vertex[]>edgeMap=graph.getAdjacencys();
- VertextwoVertex=newVertex("2");
- VertexthreeVertex=newVertex("3");
- VertexfiveVertex=newVertex("5");
- VertexsevenVertex=newVertex("7");
- VertexeightVertex=newVertex("8");
- VertexnineVertex=newVertex("9");
- VertextenVertex=newVertex("10");
- VertexelevenVertex=newVertex("11");
- vertexSet.add(twoVertex);
- vertexSet.add(threeVertex);
- vertexSet.add(fiveVertex);
- vertexSet.add(sevenVertex);
- vertexSet.add(eightVertex);
- vertexSet.add(nineVertex);
- vertexSet.add(tenVertex);
- vertexSet.add(elevenVertex);
- edgeMap.put(twoVertex,newVertex[]{elevenVertex});
- edgeMap.put(nineVertex,newVertex[]{elevenVertex,eightVertex});
- edgeMap.put(tenVertex,newVertex[]{elevenVertex,threeVertex});
- edgeMap.put(elevenVertex,newVertex[]{sevenVertex,fiveVertex});
- edgeMap.put(eightVertex,newVertex[]{sevenVertex,threeVertex});
- Vertex[]sortedVertexs=topologicalSort(graph);
- printVertex(sortedVertexs);
- }
- publicstaticvoidprintVertex(Vertex[]Vertexs){
- for(Vertexvertex:Vertexs){
- System.out.println(vertex.getName()+"discovertime:"
- +vertex.getDiscover()+"finishtime:"
- +vertex.getFinish());
- }
- }
后记
以上Java实现参考的是算法导论的深度优先排序算法。如果想对排序的精确度有更好的控制,可以在Vertex类中加一个priority属性。每一次遍历之前都针对顶点以priority即可。参考链接:维基百科
拓扑排序算法介绍
拓扑排序解决的是一系列相互依赖的事件的排序问题,比如Ant中有很多的Task,而某些Task依赖于另外的Task,编译之前需要清理空间,打包之前要先编译,但其它一些Task处理顺序可以调换(是无所谓前后,不是并行), 如何安排Task的执行顺序就可以用拓扑排序解决。熟悉Java的朋友应该都知道Spring,一个非常优秀的解决组件(Bean)依赖的框架,组件之间可能有依赖关系,也可能没有关系,如何按顺序创建组件也是相同的问题。本文使用的是图搜索算法里面的深度优先排序算法解决问题。需要特别指出的是拓扑排序算法的结果很可能有多个(不依赖的可以调换位置),而算法也可以有多种,深度优先排序算法只是其中一种而已。拓扑排序为线性排序,效率为O(|V|+|E|),其中|V|表示顶点数,|E|表示边的数量。
拓扑排序算法Java实现
图像(Graph)的Java抽象实现
图可以抽象为顶点和边,分为有向图和无向图,拓扑排序里面使用的事有向图(依赖),本文中图的边用相邻链表方法表示。每一个顶点有名字(name),颜色(color, 搜索时候用来标记处理状态),父节点(parent,搜索结束可以得到多棵树),开始处理时间(discover),结束处理时间(finish)。请注意Vertex类override了equals和hash方法。具体代码如下:
深度优先算法
遍历图的顶点,如果当前顶点还没有处理过(color为white),就处理该节点(visitVertex),处理节点的算法(visitVertex)也不难,时间维度加1,当前节点颜色置为gray(开始处理),然后优先处理其子节点(深度优先),结束之后时间维度加1,当前节点颜色置为black(结束处理)。此时就可以把该节点放到目标链表里面了(最终排好序的链表)。由于Java里面Integer值不可变(Immutable),只能选择全局变量或者自己实现时间计数器,本文选择后者(TimeRecorder)。代码如下:
- staticclassTimeRecorder{
- privateinttime=0;
- publicintgetTime(){
- returntime;
- }
- publicvoidsetTime(inttime){
- this.time=time;
- }
- }
- publicstaticVertex[]topologicalSort(Graphgraph){
- Set<Vertex>vertexSet=graph.getVertexSet();
- if(vertexSet.size()<2){
- returnvertexSet.toArray(newVertex[0]);
- }
- LinkedList<Vertex>sortedList=newLinkedList<Vertex>();
- TimeRecorderrecorder=newTimeRecorder();
- for(Vertexvertex:vertexSet){
- if(vertex.color==Color.WHITE){
- visitVertex(graph,vertex,recorder,sortedList);
- }
- }
- returnsortedList.toArray(newVertex[0]);
- }
- publicstaticvoidvisitVertex(Graphgraph,Vertexvertex,
- TimeRecorderrecorder,LinkedList<Vertex>sortedList){
- recorder.time+=1;
- vertex.color=Color.GRAY;
- vertex.discover=recorder.time;
- Map<Vertex,Vertex[]>edgeMap=graph.getAdjacencys();
- Vertex[]adjacencys=edgeMap.get(vertex);
- if(adjacencys!=null&&adjacencys.length>0){
- for(Vertexadjacency:adjacencys){
- if(adjacency.color==Color.WHITE){
- adjacency.parent=vertex;
- visitVertex(graph,adjacency,recorder,sortedList);
- }
- }
- }
- recorder.time+=1;
- vertex.color=Color.BLACK;
- vertex.finish=recorder.time;
- sortedList.addLast(vertex);
- }
构建图以及测试
我们的测试图例如下(箭头的方向表示的是依赖):
为了打印排好序的结果,实现了printVertex函数。测试代码如下:
- publicstaticvoidmain(String[]args){
- Graphgraph=newGraph();
- Set<Vertex>vertexSet=graph.getVertexSet();
- Map<Vertex,Vertex[]>edgeMap=graph.getAdjacencys();
- VertextwoVertex=newVertex("2");
- VertexthreeVertex=newVertex("3");
- VertexfiveVertex=newVertex("5");
- VertexsevenVertex=newVertex("7");
- VertexeightVertex=newVertex("8");
- VertexnineVertex=newVertex("9");
- VertextenVertex=newVertex("10");
- VertexelevenVertex=newVertex("11");
- vertexSet.add(twoVertex);
- vertexSet.add(threeVertex);
- vertexSet.add(fiveVertex);
- vertexSet.add(sevenVertex);
- vertexSet.add(eightVertex);
- vertexSet.add(nineVertex);
- vertexSet.add(tenVertex);
- vertexSet.add(elevenVertex);
- edgeMap.put(twoVertex,newVertex[]{elevenVertex});
- edgeMap.put(nineVertex,newVertex[]{elevenVertex,eightVertex});
- edgeMap.put(tenVertex,newVertex[]{elevenVertex,threeVertex});
- edgeMap.put(elevenVertex,newVertex[]{sevenVertex,fiveVertex});
- edgeMap.put(eightVertex,newVertex[]{sevenVertex,threeVertex});
- Vertex[]sortedVertexs=topologicalSort(graph);
- printVertex(sortedVertexs);
- }
- publicstaticvoidprintVertex(Vertex[]Vertexs){
- for(Vertexvertex:Vertexs){
- System.out.println(vertex.getName()+"discovertime:"
- +vertex.getDiscover()+"finishtime:"
- +vertex.getFinish());
- }
- }
后记
以上Java实现参考的是算法导论的深度优先排序算法。如果想对排序的精确度有更好的控制,可以在Vertex类中加一个priority属性。每一次遍历之前都针对顶点以priority即可。参考链接:维基百科
分享到:
相关推荐
拓扑排序的两种实现
拓扑排序,简单地说,是由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。一个表示偏序的有向图可用来表示一个流程图。它或者是一个施工流程图,或者是一个产品生产的流程图,再或是一个数据...
对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现...本程序自己手动输入图的节点,实现拓扑排序。
matlab开发-Topologicalsort。执行有向图的拓扑排序
对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v...简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序。
Implement the pseudocode presented in the lecture for both creating a graph and for topological sort. Put each algorithm into a separate function. Construct a data structure to store a graph, which ...
从文本文件中读取邻接矩阵,通过减一治的方法实现拓扑排序
假设给我们一个任意的图,它可能是也可能不是DAG(有向无圈图),推广拓扑排序算法,以使得给定有向图G的输入,它的输出是以下两者之一: (a) 一个拓扑排序,于是确定了G为DAG; 或者 (b) G中的一个圈,于是确定了G...
项目描述 Java程序,对一组部分排序的元素进行。 程序使用Kahn的算法,该算法也在Wiki页面上进行了讨论。 项目特色 通过命令行从文件读取输入。... 如果无法进行拓扑排序,则输出消息图形包含循环。
假设给我们一个任意的图,它可能是也可能不是DAG(有向无圈图),推广拓扑排序算法,以使得给定有向图G的输入,它的输出是以下两者之一: (a) 一个拓扑排序,于是确定了G为DAG; 或者 (b) G中的一个圈,于是确定了G...
这是一个图的拓扑排序的程序,是数据结构的图一章中比较重要的内容,程序已经调试通过,可以供大家参考
在AOV网中为了更好地完成工程,必须满足活动之间先后关系,需要将各活动排一个先后...拓扑排序算法void TopologicalSort(ALGraph G) 中,先输出入度为零的顶点,而后输出新的入度为零的顶点,此操作可利用栈或队列实现
拓扑排序 排序依赖项 import topological from '../index.js' ;let items = [{ name : 'jquery-plugin1' , src : 'jquery-plugin-1.2.1.js' , dep : [ 'jquery' ] } ,{ name : 'jquery' , src : 'jquery-1.6.2.js' ,...
拓扑排序 对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对...简单的说,由某个集合上的一个偏序得到该集合上的一个全序,这个操作称之为拓扑排序
JavaScript的拓扑排序算法。 参见 。 :warning: 该代码要求定义regeneratorRuntime ,例如,通过导入 。 // Sort anything that can be iterated over with `for (const [u, v] of ...)` import { sorted } from...
对于这种依赖关系,很容易将其表示成一个有向无环图(Directed Acyclic Graph,DAG,无环是一个重要条件),并将寻找其中依赖顺序的过程称为拓扑排序(topological sorting)。 拓扑排序要满足如下两个条件 每个...
对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若边(u,v)∈E(G),则u在线性序列中出现在v之前。通常,这样的线性序列称为满足拓扑...
严蔚敏数据结构与算法▲课本算法实现
严蔚敏数据结构与算法▲课本算法实现
主要设计CreateUDG函数创建图的邻接链表,其中通过LocateVex 可以定位到邻接表代表元素的数组下标并进行连接TopologicalSort函数调用链栈对图的所有结点进行拓扑排序的功能,并为计算最晚开始时间做准备, ...