圖——基本的圖演算法(三)拓撲排序
阿新 • • 發佈:2018-11-05
圖——基本的圖演算法(三)拓撲排序
1. 基本概念
對於一個有向無環圖G = (V, E)來說,其拓撲排序就是G中所有頂點的一種線性排序,這種排序滿足如下條件:如果圖G中包含邊(a, b),即由頂點a指向頂點b的有向邊,那麼在G的拓撲排序中,頂點a一定處於頂點b前面(因此如果有向圖G中包含迴路,則不可能排出這樣一個線性次序)。
2. 演算法實現
2.1 總體思想
對一個有向無環圖進行拓撲排序的基本思路是:從圖中選出一個入度為0的頂點輸出,然後刪掉這個頂點,並且刪去以這個頂點為尾的弧,然後重複上述步驟,直至全部頂點輸出。
2.2 資料結構
對於拓撲排序,由於要刪掉以某個入度為0的頂點為尾的弧,也就是要刪掉相應的邊,因此一般採用鄰接表來對圖進行表示,但要稍作修改:頂點表中的每個結點增加一項用來表示該頂點此時的入度值。具體如下:
(1)頂點表結點
typedef struct VertexListNode{
int in; //入度
int data; //該頂點的值
EdgeListNode* firstadj; //指向該頂點的邊表裡的第一個結點
};
(2)邊表結點
typedef struct EdgeListNode{
int adjId; //弧頭在頂點表中的下標
int weight; //弧的權值
EdgeListNode* next; //指向邊表中的下一個結點
};
(3)鄰接連結串列表示的圖結構
typedef struct GraphAdjList{ int vertexnumber; //頂點個數 int edgenumber; //弧的條數 VertexListNode vertextlist[Maximum]; //頂點表 };
(4)綜上,資料結構為:
#define Maximum 1000 typedef struct EdgeListNode{ int adjId; int weight; EdgeListNode* next; }; typedef struct VertexListNode{ int in; int data; EdgeListNode* firstadj; }; typedef struct GraphAdjList{ int vertexnumber; int edgenumber; VertexListNode vertextlist[Maximum]; };
2.3 具體實現
// 返回儲存了拓撲排序的vector
vector<int> ToplogicalSort(GraphAdjList g) {
int ans = 0;
queue<int>q; //用來儲存入度為0的待處理頂點
vector<int> sort_queue; //用來儲存拓撲排序結果
// 清空佇列
while(!q.empty()) {
q.pop();
}
int i, j, k;
//找出所有入度為0的頂點,入佇列
for(i=1; i<=g.vertexnumber; i++) {
if(g.vertextlist[i].in == 0) {
q.push(i);
}
}
EdgeListNode *temp;
while(!q.empty()) {
j = q.front();
q.pop();
ans++;
sort_queue.push_back(j);
temp = g.vertextlist[j].firstadj;
//遍歷其邊表,找出於其有邊相連的頂點
while(temp != NULL) {
g.vertextlist[temp->adjId].in--; //該頂點入度減一
if(g.vertextlist[temp->adjId].in == 0) {
q.push(temp->adjId);
}
temp = temp->next;
}
}
if(ans < g.vertexnumber) { //這是一個有環有向圖
sort_queue.clear(); //清空vector
}
return sort_queue;
}
2.4 測試
完整程式碼:
#include<iostream>
#include<stdio.h>
#include<string.h>
#include<map>
#include<vector>
#include<sstream>
#include<list>
#include<stdlib.h>
#include<queue>
using namespace std;
#define Maximum 1000
typedef struct EdgeListNode{
int adjId;
int weight;
EdgeListNode* next;
};
typedef struct VertexListNode{
int in;
int data;
EdgeListNode* firstadj;
};
typedef struct GraphAdjList{
int vertexnumber;
int edgenumber;
VertexListNode vertextlist[Maximum];
};
vector<int> ToplogicalSort(GraphAdjList g) {
int ans = 0;
queue<int>q;
vector<int> sort_queue;
while(!q.empty()) {
q.pop();
}
int i, j, k;
for(i=1; i<=g.vertexnumber; i++) {
if(g.vertextlist[i].in == 0) {
q.push(i);
}
}
EdgeListNode *temp;
while(!q.empty()) {
j = q.front();
q.pop();
ans++;
sort_queue.push_back(j);
temp = g.vertextlist[j].firstadj;
while(temp != NULL) {
if(--g.vertextlist[temp->adjId].in == 0) {
q.push(temp->adjId);
}
temp = temp->next;
}
}
if(ans < g.vertexnumber) {
sort_queue.clear();
}
return sort_queue;
}
int main() {
GraphAdjList g;
g.vertexnumber = 5;
g.edgenumber = 5;
int i;
for(i=1; i<6; i++) {
g.vertextlist[i].data = i;
g.vertextlist[i].firstadj = NULL;
}
g.vertextlist[1].in = g.vertextlist[4].in = 0;
g.vertextlist[5].in = g.vertextlist[3].in = 2;
g.vertextlist[2].in = 1;
EdgeListNode* t;
t = (EdgeListNode*)malloc(sizeof(EdgeListNode));
t->adjId = 3; t->next = NULL; g.vertextlist[1].firstadj = t;
t = (EdgeListNode*)malloc(sizeof(EdgeListNode));
t->adjId = 2; t->next = g.vertextlist[1].firstadj; g.vertextlist[1].firstadj = t;
t = (EdgeListNode*)malloc(sizeof(EdgeListNode));
t->adjId = 5; t->next = NULL; g.vertextlist[2].firstadj = t;
t = (EdgeListNode*)malloc(sizeof(EdgeListNode));
t->adjId = 5; t->next = NULL; g.vertextlist[3].firstadj = t;
t = (EdgeListNode*)malloc(sizeof(EdgeListNode));
t->adjId = 3; t->next = NULL; g.vertextlist[4].firstadj = t;
vector<int>v;
v = ToplogicalSort(g);
if(v.size() == 0) {
cout<<"This graph has ring"<<endl;
}
else {
for(i=0; i<v.size(); i++) {
cout<<v[i]<<" ";
}
cout<<endl;
}
return 0;
}