有向無環圖的拓撲排序


拓撲排序

    對於一個有向無環圖,我們可以這樣確定一個圖中頂點的順序: 
對於所有的u、v,若存在有向路徑u-->v,則在最后的頂點排序中u就位於v之前。這樣確定的順序就是一個圖的拓撲排序。 
    拓撲排序的特點: 
(1)所有可以到達頂點v的頂點u都位於頂點v之前; 
(2)所有從頂點v可以到達的頂點u都位於頂點v之后; 
(3)只有有向無環圖才存在拓撲排序; 
(4)一個圖的拓撲順序不唯一

實現拓撲排序

思路 
    圖中入度為0的點沒有任何點可以到達它,因此可以排在最開始(若有多個入度為0的點,他們之間的相對順序隨意); 
    因為入度為0的頂點已經排完序了,因此可以將那些入度為0的頂點去掉。去掉之后的圖中,還會存在一些入度為0的頂點,因此可以繼續采用上述的方法.... 
    到最后圖中還有一些入度均不為0的頂點,那么在這個圖中從任意一個頂點開始走下去,必然會經過每個頂點多於1次,即存在環,與前提矛盾!

實現 
    拓撲排序常用的算法是通過一個隊列存放入度為0的點,每次取出隊列頭元素,訪問該頂點,然后然后將該點連接的所有邊消除,再將新圖的入度為0的點加入隊列...直到圖中不存在入度為0的點。

#define MAX_NODE 1000
#define MAX_EDGE_NUM 100000
struct Edge{
	int to;
	int w;
	int next;
};
Edge gEdges[MAX_EDGE_NUM];
int gHead[MAX_NODE];
bool gVisited[MAX_NODE];
int gInDegree[MAX_NODE];
int gEdgeCount;
void InsertEdge(int u, int v, int w){
	int e = gEdgeCount++;
	gEdges[e].to = v;
	gEdges[e].w = w;
	gEdges[e].next = gHead[u];
	gHead[u] = e;
	gInDegree[v] ++;	//入度加1
}
void TopoSort(int n /*節點數目*/){
	queue<int> zero_indegree_queue;
	for (int i = 0; i < n; i++){
        if (gInDegree[i] == 0) zero_indegree_queue.push(i); } memset(gVisited, false, sizeof(gVisited)); while (!zero_indegree_queue.empty()){ int u = zero_indegree_queue.front(); zero_indegree_queue.pop(); gVisited[u] = true; //輸出u for (int e = gHead[u]; e != -1; e = gEdges[e].next){ int v = gEdges[e].to; gInDegree[v] --; if (gInDegree[v] == 0){ zero_indegree_queue.push(v); } } } for (int i = 0; i < n; i++){ if (!gVisited[i]){ //存在環! 無法形成拓撲序 } } }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM