1. 程式人生 > >圖——基本的圖演算法(三)拓撲排序

圖——基本的圖演算法(三)拓撲排序

圖——基本的圖演算法(三)拓撲排序

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;
}