拓扑排序(Topologicalsort)之Java实现

目录(?)[+]

拓扑排序算法介绍

拓扑排序解决的是一系列相互依赖的事件的排序问题,比如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方法。具体代码如下:

  1. enumColor{
  2. WHITE,GRAY,BLACK
  3. }
  4. staticclassVertex{
  5. privateStringname;
  6. privateColorcolor;
  7. privateVertexparent;
  8. privateintdiscover;
  9. privateintfinish;
  10. publicVertex(Stringname){
  11. this.name=name;
  12. this.color=Color.WHITE;
  13. }
  14. publicStringgetName(){
  15. returnname;
  16. }
  17. publicvoidsetName(Stringname){
  18. this.name=name;
  19. }
  20. publicColorgetColor(){
  21. returncolor;
  22. }
  23. publicvoidsetColor(Colorcolor){
  24. this.color=color;
  25. }
  26. publicVertexgetParent(){
  27. returnparent;
  28. }
  29. publicvoidsetParent(Vertexparent){
  30. this.parent=parent;
  31. }
  32. publicintgetDiscover(){
  33. returndiscover;
  34. }
  35. publicvoidsetDiscover(intdiscover){
  36. this.discover=discover;
  37. }
  38. publicintgetFinish(){
  39. returnfinish;
  40. }
  41. publicvoidsetFinish(intfinish){
  42. this.finish=finish;
  43. }
  44. @Override
  45. publicinthashCode(){
  46. finalintprime=31;
  47. intresult=1;
  48. result=prime*result+((name==null)?0:name.hashCode());
  49. returnresult;
  50. }
  51. @Override
  52. publicbooleanequals(Objectobj){
  53. if(this==obj)
  54. returntrue;
  55. if(obj==null)
  56. returnfalse;
  57. if(getClass()!=obj.getClass())
  58. returnfalse;
  59. Vertexother=(Vertex)obj;
  60. if(name==null){
  61. if(other.name!=null)
  62. returnfalse;
  63. }elseif(!name.equals(other.name))
  64. returnfalse;
  65. returntrue;
  66. }
  67. }
  68. staticclassGraph{
  69. privateSet<Vertex>vertexSet=newHashSet<Vertex>();
  70. //相邻的节点
  71. privateMap<Vertex,Vertex[]>adjacencys=newHashMap<Vertex,Vertex[]>();
  72. publicSet<Vertex>getVertexSet(){
  73. returnvertexSet;
  74. }
  75. publicvoidsetVertexSet(Set<Vertex>vertexSet){
  76. this.vertexSet=vertexSet;
  77. }
  78. publicMap<Vertex,Vertex[]>getAdjacencys(){
  79. returnadjacencys;
  80. }
  81. publicvoidsetAdjacencys(Map<Vertex,Vertex[]>adjacencys){
  82. this.adjacencys=adjacencys;
  83. }
  84. }

深度优先算法

遍历图的顶点,如果当前顶点还没有处理过(color为white),就处理该节点(visitVertex),处理节点的算法(visitVertex)也不难,时间维度加1,当前节点颜色置为gray(开始处理),然后优先处理其子节点(深度优先),结束之后时间维度加1,当前节点颜色置为black(结束处理)。此时就可以把该节点放到目标链表里面了(最终排好序的链表)。由于Java里面Integer值不可变(Immutable),只能选择全局变量或者自己实现时间计数器,本文选择后者(TimeRecorder)。代码如下:

  1. staticclassTimeRecorder{
  2. privateinttime=0;
  3. publicintgetTime(){
  4. returntime;
  5. }
  6. publicvoidsetTime(inttime){
  7. this.time=time;
  8. }
  9. }
  10. publicstaticVertex[]topologicalSort(Graphgraph){
  11. Set<Vertex>vertexSet=graph.getVertexSet();
  12. if(vertexSet.size()<2){
  13. returnvertexSet.toArray(newVertex[0]);
  14. }
  15. LinkedList<Vertex>sortedList=newLinkedList<Vertex>();
  16. TimeRecorderrecorder=newTimeRecorder();
  17. for(Vertexvertex:vertexSet){
  18. if(vertex.color==Color.WHITE){
  19. visitVertex(graph,vertex,recorder,sortedList);
  20. }
  21. }
  22. returnsortedList.toArray(newVertex[0]);
  23. }
  24. /**
  25. *深度优先搜索(DepthFirstSearch)
  26. */
  27. publicstaticvoidvisitVertex(Graphgraph,Vertexvertex,
  28. TimeRecorderrecorder,LinkedList<Vertex>sortedList){
  29. recorder.time+=1;
  30. vertex.color=Color.GRAY;
  31. vertex.discover=recorder.time;
  32. Map<Vertex,Vertex[]>edgeMap=graph.getAdjacencys();
  33. Vertex[]adjacencys=edgeMap.get(vertex);
  34. if(adjacencys!=null&&adjacencys.length>0){
  35. for(Vertexadjacency:adjacencys){
  36. if(adjacency.color==Color.WHITE){
  37. adjacency.parent=vertex;
  38. visitVertex(graph,adjacency,recorder,sortedList);
  39. }
  40. }
  41. }
  42. recorder.time+=1;
  43. vertex.color=Color.BLACK;
  44. vertex.finish=recorder.time;
  45. sortedList.addLast(vertex);
  46. }

构建图以及测试

我们的测试图例如下(箭头的方向表示的是依赖):


为了打印排好序的结果,实现了printVertex函数。测试代码如下:

  1. publicstaticvoidmain(String[]args){
  2. Graphgraph=newGraph();
  3. Set<Vertex>vertexSet=graph.getVertexSet();
  4. Map<Vertex,Vertex[]>edgeMap=graph.getAdjacencys();
  5. VertextwoVertex=newVertex("2");
  6. VertexthreeVertex=newVertex("3");
  7. VertexfiveVertex=newVertex("5");
  8. VertexsevenVertex=newVertex("7");
  9. VertexeightVertex=newVertex("8");
  10. VertexnineVertex=newVertex("9");
  11. VertextenVertex=newVertex("10");
  12. VertexelevenVertex=newVertex("11");
  13. vertexSet.add(twoVertex);
  14. vertexSet.add(threeVertex);
  15. vertexSet.add(fiveVertex);
  16. vertexSet.add(sevenVertex);
  17. vertexSet.add(eightVertex);
  18. vertexSet.add(nineVertex);
  19. vertexSet.add(tenVertex);
  20. vertexSet.add(elevenVertex);
  21. edgeMap.put(twoVertex,newVertex[]{elevenVertex});
  22. edgeMap.put(nineVertex,newVertex[]{elevenVertex,eightVertex});
  23. edgeMap.put(tenVertex,newVertex[]{elevenVertex,threeVertex});
  24. edgeMap.put(elevenVertex,newVertex[]{sevenVertex,fiveVertex});
  25. edgeMap.put(eightVertex,newVertex[]{sevenVertex,threeVertex});
  26. Vertex[]sortedVertexs=topologicalSort(graph);
  27. printVertex(sortedVertexs);
  28. }
  29. publicstaticvoidprintVertex(Vertex[]Vertexs){
  30. for(Vertexvertex:Vertexs){
  31. System.out.println(vertex.getName()+"discovertime:"
  32. +vertex.getDiscover()+"finishtime:"
  33. +vertex.getFinish());
  34. }
  35. }

后记

以上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方法。具体代码如下:

  1. enumColor{
  2. WHITE,GRAY,BLACK
  3. }
  4. staticclassVertex{
  5. privateStringname;
  6. privateColorcolor;
  7. privateVertexparent;
  8. privateintdiscover;
  9. privateintfinish;
  10. publicVertex(Stringname){
  11. this.name=name;
  12. this.color=Color.WHITE;
  13. }
  14. publicStringgetName(){
  15. returnname;
  16. }
  17. publicvoidsetName(Stringname){
  18. this.name=name;
  19. }
  20. publicColorgetColor(){
  21. returncolor;
  22. }
  23. publicvoidsetColor(Colorcolor){
  24. this.color=color;
  25. }
  26. publicVertexgetParent(){
  27. returnparent;
  28. }
  29. publicvoidsetParent(Vertexparent){
  30. this.parent=parent;
  31. }
  32. publicintgetDiscover(){
  33. returndiscover;
  34. }
  35. publicvoidsetDiscover(intdiscover){
  36. this.discover=discover;
  37. }
  38. publicintgetFinish(){
  39. returnfinish;
  40. }
  41. publicvoidsetFinish(intfinish){
  42. this.finish=finish;
  43. }
  44. @Override
  45. publicinthashCode(){
  46. finalintprime=31;
  47. intresult=1;
  48. result=prime*result+((name==null)?0:name.hashCode());
  49. returnresult;
  50. }
  51. @Override
  52. publicbooleanequals(Objectobj){
  53. if(this==obj)
  54. returntrue;
  55. if(obj==null)
  56. returnfalse;
  57. if(getClass()!=obj.getClass())
  58. returnfalse;
  59. Vertexother=(Vertex)obj;
  60. if(name==null){
  61. if(other.name!=null)
  62. returnfalse;
  63. }elseif(!name.equals(other.name))
  64. returnfalse;
  65. returntrue;
  66. }
  67. }
  68. staticclassGraph{
  69. privateSet<Vertex>vertexSet=newHashSet<Vertex>();
  70. //相邻的节点
  71. privateMap<Vertex,Vertex[]>adjacencys=newHashMap<Vertex,Vertex[]>();
  72. publicSet<Vertex>getVertexSet(){
  73. returnvertexSet;
  74. }
  75. publicvoidsetVertexSet(Set<Vertex>vertexSet){
  76. this.vertexSet=vertexSet;
  77. }
  78. publicMap<Vertex,Vertex[]>getAdjacencys(){
  79. returnadjacencys;
  80. }
  81. publicvoidsetAdjacencys(Map<Vertex,Vertex[]>adjacencys){
  82. this.adjacencys=adjacencys;
  83. }
  84. }

深度优先算法

遍历图的顶点,如果当前顶点还没有处理过(color为white),就处理该节点(visitVertex),处理节点的算法(visitVertex)也不难,时间维度加1,当前节点颜色置为gray(开始处理),然后优先处理其子节点(深度优先),结束之后时间维度加1,当前节点颜色置为black(结束处理)。此时就可以把该节点放到目标链表里面了(最终排好序的链表)。由于Java里面Integer值不可变(Immutable),只能选择全局变量或者自己实现时间计数器,本文选择后者(TimeRecorder)。代码如下:

  1. staticclassTimeRecorder{
  2. privateinttime=0;
  3. publicintgetTime(){
  4. returntime;
  5. }
  6. publicvoidsetTime(inttime){
  7. this.time=time;
  8. }
  9. }
  10. publicstaticVertex[]topologicalSort(Graphgraph){
  11. Set<Vertex>vertexSet=graph.getVertexSet();
  12. if(vertexSet.size()<2){
  13. returnvertexSet.toArray(newVertex[0]);
  14. }
  15. LinkedList<Vertex>sortedList=newLinkedList<Vertex>();
  16. TimeRecorderrecorder=newTimeRecorder();
  17. for(Vertexvertex:vertexSet){
  18. if(vertex.color==Color.WHITE){
  19. visitVertex(graph,vertex,recorder,sortedList);
  20. }
  21. }
  22. returnsortedList.toArray(newVertex[0]);
  23. }
  24. /**
  25. *深度优先搜索(DepthFirstSearch)
  26. */
  27. publicstaticvoidvisitVertex(Graphgraph,Vertexvertex,
  28. TimeRecorderrecorder,LinkedList<Vertex>sortedList){
  29. recorder.time+=1;
  30. vertex.color=Color.GRAY;
  31. vertex.discover=recorder.time;
  32. Map<Vertex,Vertex[]>edgeMap=graph.getAdjacencys();
  33. Vertex[]adjacencys=edgeMap.get(vertex);
  34. if(adjacencys!=null&&adjacencys.length>0){
  35. for(Vertexadjacency:adjacencys){
  36. if(adjacency.color==Color.WHITE){
  37. adjacency.parent=vertex;
  38. visitVertex(graph,adjacency,recorder,sortedList);
  39. }
  40. }
  41. }
  42. recorder.time+=1;
  43. vertex.color=Color.BLACK;
  44. vertex.finish=recorder.time;
  45. sortedList.addLast(vertex);
  46. }

构建图以及测试

我们的测试图例如下(箭头的方向表示的是依赖):


为了打印排好序的结果,实现了printVertex函数。测试代码如下:

  1. publicstaticvoidmain(String[]args){
  2. Graphgraph=newGraph();
  3. Set<Vertex>vertexSet=graph.getVertexSet();
  4. Map<Vertex,Vertex[]>edgeMap=graph.getAdjacencys();
  5. VertextwoVertex=newVertex("2");
  6. VertexthreeVertex=newVertex("3");
  7. VertexfiveVertex=newVertex("5");
  8. VertexsevenVertex=newVertex("7");
  9. VertexeightVertex=newVertex("8");
  10. VertexnineVertex=newVertex("9");
  11. VertextenVertex=newVertex("10");
  12. VertexelevenVertex=newVertex("11");
  13. vertexSet.add(twoVertex);
  14. vertexSet.add(threeVertex);
  15. vertexSet.add(fiveVertex);
  16. vertexSet.add(sevenVertex);
  17. vertexSet.add(eightVertex);
  18. vertexSet.add(nineVertex);
  19. vertexSet.add(tenVertex);
  20. vertexSet.add(elevenVertex);
  21. edgeMap.put(twoVertex,newVertex[]{elevenVertex});
  22. edgeMap.put(nineVertex,newVertex[]{elevenVertex,eightVertex});
  23. edgeMap.put(tenVertex,newVertex[]{elevenVertex,threeVertex});
  24. edgeMap.put(elevenVertex,newVertex[]{sevenVertex,fiveVertex});
  25. edgeMap.put(eightVertex,newVertex[]{sevenVertex,threeVertex});
  26. Vertex[]sortedVertexs=topologicalSort(graph);
  27. printVertex(sortedVertexs);
  28. }
  29. publicstaticvoidprintVertex(Vertex[]Vertexs){
  30. for(Vertexvertex:Vertexs){
  31. System.out.println(vertex.getName()+"discovertime:"
  32. +vertex.getDiscover()+"finishtime:"
  33. +vertex.getFinish());
  34. }
  35. }

后记

以上Java实现参考的是算法导论的深度优先排序算法。如果想对排序的精确度有更好的控制,可以在Vertex类中加一个priority属性。每一次遍历之前都针对顶点以priority即可。参考链接:维基百科

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java实现拓扑排序可以使用深度优先排序算法。首先,创建一个顶点类Vertex,其中包含一个标签属性label。然后,建立一个图像(Graph)的Java抽象实现,该实现包括图的顶点和边的信息。通过遍历图的顶点和边,使用深度优先搜索算法来进行拓扑排序。在排序之前,可以根据需要给顶点设置优先级属性,以控制排序的精确度。实现的时间复杂度为O(|V| |E|),其中|V|表示顶点数,|E|表示边的数量。可以参考算法导论中深度优先排序算法的Java实现。 下面是一个简单的Java实现示例: ```java import java.util.ArrayList; import java.util.List; import java.util.Stack; public class TopologicalSort { private List<Vertex> sortedVertices; public List<Vertex> topologicalSort(Graph graph) { sortedVertices = new ArrayList<>(); Stack<Vertex> stack = new Stack<>(); for (Vertex vertex : graph.getVertices()) { if (!vertex.isVisited()) { dfs(vertex, stack); } } return sortedVertices; } private void dfs(Vertex vertex, Stack<Vertex> stack) { vertex.setVisited(true); for (Vertex neighbor : vertex.getNeighbors()) { if (!neighbor.isVisited()) { dfs(neighbor, stack); } } stack.push(vertex); sortedVertices.add(vertex); } } class Vertex { private char label; private boolean visited; private List<Vertex> neighbors; public Vertex(char label) { this.label = label; this.visited = false; this.neighbors = new ArrayList<>(); } // getters and setters // ... } class Graph { private List<Vertex> vertices; public List<Vertex> getVertices() { return vertices; } // other methods // ... } ``` 以上是一个简单的Java实现示例,其中Graph类表示图,Vertex类表示顶点。在TopologicalSort类中,topologicalSort方法使用深度优先搜索算法进行拓扑排序,最终返回排序后的顶点列表。可以根据实际需求对代码进行修改和优化。 参考链接:维基百科提供了更多关于拓扑排序的信息,可以进一步了解。中的参考资料还提供了Graph和Vertex类的代码示例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值