拓扑排序的两种算法

1. 拓扑排序主要有两种算法:方法1:《算法导论》上给出的DFS+时间戳;方法2:求顶点入度+贪心算法。

2. 两种算法的代码分别如下:

View Code
  1 static int f[100]={0};
  2 static int ftime=0;
  3 //递归深度优先搜索
  4 template<typename vertexNametype, typename weight>
  5 void ALGraph<vertexNametype, weight>::DFS()
  6 {
  7     int n=getVertexNumber();
  8     bool *visited=new bool[n];
  9     for (int i=0;i<n;i++)
 10     {
 11         visited[i]=false;
 12     }
 13     for (int i=0;i<n;i++)
 14     {
 15         if (!visited[i])
 16         {
 17             DFS(i,visited);
 18             cout<<endl;
 19         }
 20     }
 21     delete[] visited;
 22 }
 23 
 24 
 25 
 26 template<typename vertexNametype, typename weight>
 27 void ALGraph<vertexNametype, weight>::DFS(int vertexNumber,bool visited[])
 28 {
 29     cout<<getData(vertexNumber)<<"  ";
 30     visited[vertexNumber]=true;
 31     Edge<weight> *p=m_vertexArray.at(vertexNumber).pAdjEdges;
 32     while(p!=NULL)
 33     {
 34         if (!visited[p->nDestVertex])
 35         {
 36             DFS(p->nDestVertex,visited);
 37         }
 38         p=p->pNextEdge;
 39     }
 40     //每一个节点访问结束之后,都记录其访问时间。
 41     f[vertexNumber]=ftime;
 42     ftime++;
 43 }
 44 //拓扑排序算法一的思想是:用DFS遍历整个图,记录各个节点
 45 //的完成时间,然后按各个节点的完成时间逆序排列,就得到了
 46 //拓扑排序序列
 47 template<typename vertexNametype, typename weight> 
 48 void ALGraph<vertexNametype,weight>::Topological_sort1()
 49 {
 50     DFS();
 51     int vectexNo=getVertexNumber();
 52     for (int i=0;i<vectexNo;i++)
 53     {
 54         cout<<i<<" : "<<f[i]<<"   ";
 55     }
 56     cout<<endl;
 57     int *tp=new int[vectexNo];
 58     //按访问时间逆序排列
 59     for (int i=0;i<vectexNo;i++)
 60     {
 61         tp[vectexNo-f[i]-1]=i;
 62     }
 63     for (int i=0;i<vectexNo;i++)
 64     {
 65         cout<<getData(tp[i])<<"  ";
 66     }
 67     cout<<endl;
 68     delete[] tp;
 69 }
 70 
 71 //求一个图中所有节点的入度
 72 template<typename vertexNametype, typename weight>
 73 void ALGraph<vertexNametype,weight>::FindIndegree(INOUT int* &Ind)
 74 {
 75     assert(Ind);
 76     int vertextNo=getVertexNumber();
 77     for (int i=0;i<vertextNo;i++)
 78     {
 79         Edge<weight> *pE=m_vertexArray.at(i).pAdjEdges;
 80         while(pE)
 81         {
 82             Ind[pE->nDestVertex]++;
 83             pE=pE->pNextEdge;
 84         }
 85     }
 86 }
 87 
 88 //拓扑排序2:方法一
 89 //首先找到入度为0的节点,访问这个节点,并将这个节点
 90 //的所有出边的邻接顶点的入读减1,访问这个顶点;下一步
 91 //继续寻找入度为0的顶点,直到所有的节点均访问玩位置或者
 92 //图中存在环
 93 //时间复杂度为:O(v2)
 94 //template<typename vertexNametype, typename weight> 
 95 //void ALGraph<vertexNametype,weight>::Topological_sort2()
 96 //{
 97 //    int vectexNo=getVertexNumber();
 98 //    int *InDegree=new int[vectexNo];
 99 //    for (int i=0;i<vectexNo;i++)
100 //    {
101 //        InDegree[i]=0;
102 //    }
103 //    FindIndegree(InDegree);
104 //    for (int i=0;i<vectexNo;i++)
105 //    {
106 //        cout<<getData(i)<<":"<<InDegree[i]<<"  ";
107 //    }
108 //    cout<<endl;
109 //    bool *visited=new bool[vectexNo];
110 //    vector<vertexNametype> top;
111 //    for (int i=0;i<vectexNo;i++)
112 //    {
113 //        visited[i]=false;
114 //    }
115 //    int count=0;
116 //    while(count++<vectexNo)
117 //    {
118 //        int IndexZero=0;
119 //        for (;IndexZero<vectexNo;IndexZero++)
120 //        {
121 //            if (InDegree[IndexZero]==0 && !visited[IndexZero])
122 //            {
123 //                break;
124 //            }
125 //        }
126 //        if (IndexZero>=vectexNo)
127 //        {
128 //            break;
129 //        }
130 //        visited[IndexZero]=true;
131 //        top.push_back(getData(IndexZero));
132 //        Edge<weight>* pE=m_vertexArray.at(IndexZero).pAdjEdges;
133 //        while(pE)
134 //        {
135 //            InDegree[pE->nDestVertex]--;
136 //            pE=pE->pNextEdge;
137 //        }
138 //    }
139 //    if (count<vectexNo)
140 //    {
141 //        cout<<"Graph Has a cycle!!!"<<endl;
142 //        return ;
143 //    }
144 //    for (int i=0;i<vectexNo;i++)
145 //    {
146 //        cout<<top[i]<<"  ";
147 //    }
148 //    cout<<endl;
149 //}
150 
151 
152 //在方案一中,每次寻找节点入度为0的节点,一个for
153 //循环时间复杂度为O(v),改用queue每次将入读为0的节点
154 //存入队列,省去了下一步寻找入读为0的顶点的过程
155 template<typename vertexNametype, typename weight> 
156 void ALGraph<vertexNametype,weight>::Topological_sort2()
157 {
158     int vectexNo=getVertexNumber();
159     int *InDegree=new int[vectexNo];
160     for (int i=0;i<vectexNo;i++)
161     {
162         InDegree[i]=0;
163     }
164     FindIndegree(InDegree);
165     
166     queue<int> qu;
167     int IndexZero=0;
168     //首先将途中所有入读为0的顶点存入队列
169     for (;IndexZero<vectexNo;IndexZero++)
170     {
171         if (InDegree[IndexZero]==0)
172         {
173             qu.push(IndexZero);
174         }
175     }
176     vector<vertexNametype> top;
177     while(!qu.empty())
178     {
179         IndexZero=qu.front();
180         qu.pop();
181         top.push_back(getData(IndexZero));
182         Edge<weight>* pE=m_vertexArray.at(IndexZero).pAdjEdges;
183         while(pE)
184         {
185             InDegree[pE->nDestVertex]--;
186             if (InDegree[pE->nDestVertex]==0)
187             {
188                 qu.push(pE->nDestVertex);
189             }
190             pE=pE->pNextEdge;
191         }
192     }
193     if (top.size()<vectexNo)
194     {
195         cout<<"Graph Has a cycle!!!"<<endl;
196         return ;
197     }
198     for (int i=0;i<vectexNo;i++)
199     {
200         cout<<top[i]<<"  ";
201     }
202     cout<<endl;
203 }

3. 有人说利用DFS做拓扑排序算法有错,但是本人目前没发现这个算法有什么错误。
4. 拓扑排序可以做很多事情:如判断图中有没有环(利用方法2);排课程表(比如学C++之前一定要先学习C语言)。

5. 方法2的两种实现只有细微的差别,实现2更好一点,时间复杂度低,代码简洁。

6. 算法有不当之处,欢迎指正。

7. 算法测试使用图如下:

8. 程序运行结果(图的创建等基本程序参照随笔:图的相关算法):

  

A B C D E F G分别对应V1 V2 ... V7

posted @ 2012-07-12 12:32  kasuosuo  阅读(1366)  评论(0编辑  收藏  举报