拓撲排序

      拓撲排序是將一個有向無環圖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的話就說名 該圖有環,原理自己想。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章