有向图(拓扑排序算法)

     对一个有向无环图(Directed Acyclic Graph简称DAG)G进行拓扑排序,是将G中所有顶点排成一个线性序列,使得图中任意一对顶点u和v,若<u,v> ∈E(G),则u在线性序列中出现在v之前。
     通常,这样的线性序列称为满足拓扑次序(TopoiSicai Order)的序列,简称拓扑序列
  注意:
     ①若将图中顶点按拓扑次序排成一行,则图中所有的有向边均是从左指向右的。
     ②若图中存在有向环,则不可能使顶点满足拓扑次序。
     ③一个DAG的拓扑序列通常表示某种方案切实可行。

下面是Java实现:

  1 package zieckey.datastructure.study.graph;
  2 
  3 /**
  4  * 有方向图
  5  *
  6  * @author zieckey
  7  */
  8 public class DirectedGraph
  9 {
 10     private final int    MAX_VERTS    = 20;
 11     private Vertex[]    vertexList;        // array of vertices
 12 
 13     private int[][]        adjMat;            // adjacency matrix
 14 
 15     private int            nVerts;            // current number of vertices
 16 
 17     private char[]        sortedArray;        // sorted vert labels
 18 
 19 
 20     /**
 21      * 默认构造函数 初始化邻接矩阵
 22      */
 23     public DirectedGraph( )
 24     {
 25         vertexList = new Vertex[MAX_VERTS];
 26         sortedArray = new char[MAX_VERTS];
 27         // 图的邻接矩阵adjacency matrix
 28 
 29         adjMat = new int[MAX_VERTS][MAX_VERTS];
 30         nVerts = 0;
 31         for ( int j = 0; j < MAX_VERTS; j++ )
 32         {
 33             // set adjacency
 34 
 35             for ( int k = 0; k < MAX_VERTS; k++ )
 36             {
 37                 adjMat[j][k] = 0;
 38             }
 39         }
 40     }
 41     
 42     /**
 43      * 对有向图进行拓扑排序
 44      *
 45      * 无后继的顶点优先拓扑排序方法
 46      * 1、思想方法
 47      * 该方法的每一步均是输出当前无后继(即出度为0)的顶点。
 48      * 对于一个DAG,按此方法输出的序列是逆拓扑次序。
 49      * 因此设置一个栈(或向量)T来保存输出的顶点序列,即可得到拓扑序列。
 50      * 若T是栈,则每当输出顶点时,只需做人栈操作,排序完成时将栈中顶点依次出栈即可得拓扑序列。
 51      * 若T是向量,则将输出的顶点从T[n-1]开始依次从后往前存放,即可保证T中存储的顶点是拓扑序列。
 52      */
 53     public void nonSuccFirstToplogicalSort()
 54     {
 55         int orig_nVerts = nVerts;
 56         while(nVerts>0)
 57         {
 58             int delVertex = getNoSuccessorVertex();
 59             if ( -1 == delVertex )
 60             {
 61                 System.out.println("Error: This graph has cycles! It cannot be toplogical sorted.");
 62                 return;
 63             }
 64             
 65             sortedArray[nVerts-1= vertexList[delVertex].label;
 66             deleteVertex( delVertex );
 67         }
 68         
 69         System.out.print("Topologically sorted order: ");
 70         for(int j=0; j<orig_nVerts; j++)
 71         {
 72             System.out.print( sortedArray[j] );
 73         }
 74         System.out.println("");
 75     }
 76     
 77     /**
 78      * 找到没有后继节点的节点
 79      * @return
 80      */
 81     public int getNoSuccessorVertex()
 82     {
 83         boolean isEdge;
 84         for ( int row = 0; row < nVerts; row++ )
 85         {
 86             isEdge = false;
 87             for ( int column = 0; column < nVerts; column++ )
 88             {
 89                 if ( adjMat[row][column]>0 )//大于0,表明有边指向其他点,说明有后继节点
 90 
 91                 {    
 92                     isEdge = true;
 93                     break;                    //OK,继续下一个节点
 94 
 95                 }
 96             }
 97             
 98             if ( false == isEdge )//没有边,表明没有后继节点
 99 
100             {
101                 return row;
102             }
103         }
104         return -1;
105     }
106     
107     /**
108      * 删除一个节点
109      * @param delVertex
110      */
111     public void deleteVertex( int delVertex )
112     {
113         if ( delVertex != nVerts-1 )//如果不是最后一个节点
114 
115         {
116             //在节点列表中删除这个节点,所有后面的节点前移一格
117 
118             for ( int i = delVertex; i < nVerts-1; i++ )
119             {
120                 vertexList[i] = vertexList[i+1];
121             }
122             
123             // 删除邻接矩阵的delVertex行和列,即所有后面的行和列都向前移动一格
124 
125             // 所有delVertex行后的行,向上一个格
126 
127             for ( int row = delVertex; row < nVerts - 1; row++ )
128             {
129                 for ( int column = 0; column < nVerts; column++ )
130                 {
131                     adjMat[row][column] = adjMat[row + 1][column];
132                 }
133             }
134             
135             // 所有delVertex列后的列,向左一个格
136 
137             for ( int column = delVertex; column < nVerts; column++ )
138             {
139                 for ( int row = 0; row < nVerts - 1; row++ )                
140                 {
141                     adjMat[row][column] = adjMat[row][column+1];
142                 }
143             }
144         }
145         
146         nVerts--;//减少一个节点
147 
148     }
149     
150     /**
151      * 添加一个节点
152      *
153      * @param lab
154      */
155     public void addVertex( char lab ) // argument is label
156 
157     {
158         vertexList[nVerts++ ] = new Vertex( lab );
159     }
160 
161     /**
162      * 添加一条边
163      *
164      * @param start
165      * 起始点
166      * @param end
167      * 终点
168      */
169     public void addEdge( int start, int end )
170     {
171         adjMat[start][end] = 1;
172     }
173 
174     /**
175      * 添加一条边
176      *
177      * @param start
178      * 起始点
179      * @param end
180      * 终点
181      */
182     public void addEdge( char startVertex, char endVertex )
183     {
184         int start = getIndexByLabel( startVertex );
185         int end = getIndexByLabel( endVertex );
186         if ( -1 != start && -1 != end )
187         {
188             adjMat[start][end] = 1;
189         }
190     }
191     
192     /**
193      * 显示一个节点
194      *
195      * @param v
196      */
197     public void displayVertex( int v )
198     {
199         System.out.print( vertexList[v].label );
200     }
201 
202     public int getIndexByLabel( char lable )
203     {
204         for ( int i = 0; i < vertexList.length; i++ )
205         {
206             if ( lable == vertexList[i].label )
207             {
208                 return i;
209             }
210         }
211 
212         // 没有这个节点
213 
214         return -1;
215     }
216 }

posted @ 2009-04-21 09:19  Z.W.  阅读(1063)  评论(0编辑  收藏  举报