拓撲排序是將一個有向無環圖G的點進行排序形成一個線性序列,這個線性序列滿足:對於途中任意一對頂點,若邊(u,v) E (G),則再線性序列中 u 一定在v的前面,我們將這樣的線性序列稱爲滿足拓撲次序的序列。
算法很簡單:
1 首先先在所有點中找到入度爲 0 的點 將它存在一個名爲 T的隊列中.
2 然後將 T隊列中第一個點u所指向的所有點的入度均 減 1 然後將 u 存入 另一個 隊列Q(此隊列儲存拓撲排序的結果).然後繼續遍歷圖的所有點將入度爲 0 的點 存在T隊列中.
3 重複1 ,2知道T隊列中沒有元素爲止;
以代碼的形式實現一下:(沒看過鄰接表存圖的可以先看一下上篇文章)
#include<stdio.h>
#include<string.h>
struct {
int to;
int next;
int value;
}edges[100];
int cnt,heads[100],p[100],flag[100];
void init (){
cnt = 0;
memset(heads,-1,sizeof(heads));
memset(p,0,sizeof(p));
memset(flag,-1,sizeof(flag));
}
void add(int u,int v,int value){
edges[cnt].to = v;
edges[cnt].value = value;
edges[cnt].next = heads[u];
p[v] ++; //在利用鄰接表圖的過程中將點的入度計算一下
heads[u] = cnt++;
}
void tupu(int n){
int T[100],Q[100]; //T 暫存入度爲零的點,Q 儲存拓撲排序結果,但可以將 T 與 Q 合併 一下
int i,j,head=0,tail=0,tail2=0;
for (i=1;i<=n;i++)
{
if (p[i]==0) //第一步尋找 入讀爲零的點
{
T[tail++] = i;
flag[i] = 1; //將存入 T 的點標記一下 免得 重複儲存
}
}
while (head < tail)
{
j = heads[T[head]];
while(j!=-1) //將與點T[head]關聯的點的入度減1
{
p[edges[j].to]--;
j = edges[j].next;
}
Q[tail2++] = T[head++]; //將結果儲存在Q隊列
for (i=1;i<=n;i++) //繼續尋找入度爲 0 的點
{
if (flag[i]==-1&&p[i]==0)
{
T[tail++] = i;
flag[i] = 1;
}
}
}
printf("------------------\n");
for (i=0;i<tail2;i++) //打印結果
printf("%d ",Q[i]);
}
int main (){
int n, m, i, a, b, c = 0;
scanf("%d%d",&n,&m);
init();
for (i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
add(a,b,c);
}
tupu(n);
}
拓撲排序還可以判斷一個有向圖是否有環 : 若最終 Q 隊列中存的點少於n的話就說名 該圖有環,原理自己想。