拓撲排序的意思:

  對一個有向無環圖(Directed Acyclic Graph簡稱DAG)G進行拓撲排序,是將G中所有頂點排成一個線性序列,使得圖中任意一對頂點u和v,若邊(u,v)∈E(G),則u在線性序列中出現在v之前。通常,這樣的線性序列稱為滿足拓撲次序(Topological Order)的序列,簡稱拓撲序列。

  一個較大的工程往往被劃分成許多子工程,我們把這些子工程稱作活動(activity)。在整個工程中,有些子工程(活動)必須在其它有關子工程完成之後才能開始,也就是説,一個子工程的開始是以它的所有前序子工程的結束為先決條件的,但有些子工程沒有先決條件,可以安排在任何時間開始。為了形象地反映出整個工程中各個子工程(活動)之間的先後關係,可用一個有向圖來表示,圖中的頂點代表活動(子工程),圖中的有向邊代表活動的先後關係,即有向邊的起點的活動是終點活動的前序活動,只有當起點活動完成之後,其終點活動才能進行。通常,我們把這種頂點表示活動、邊表示活動間先後關係的有向圖稱做頂點活動網(Activity On Vertex network),簡稱AOV網。 

  在AOV網中,若不存在迴路,則所有活動可排列成一個線性序列,使得每個活動的所有前驅活動都排在該活動的前面,我們把此序列叫做拓撲序列(Topological order),由AOV網構造拓撲序列的過程叫做拓撲排序(Topological sort)。AOV網的拓撲序列不是唯一的,滿足上述定義的任一線性序列都稱作它的拓撲序列。

由AOV網構造出拓撲序列的實際意義是:如果按照拓撲序列中的頂點次序,在開始每一項活動時,能夠保證它的所有前驅活動都已完成,從而使整個工程順序進行,不會出現衝突的情況。

 

拓撲排序的步驟: 

  由AOV網構造拓撲序列的拓撲排序算法主要是循環執行以下兩步,直到不存在入度為0的頂點為止。

    (1) 選擇一個入度為0的頂點並輸出之;

    (2) 從網中刪除此頂點及所有出邊。

  循環結束後,若輸出的頂點數小於網中的頂點數,則輸出“有迴路”信息,否則輸出的頂點序列就是一種拓撲序列

 

拓撲排序排序:

/**
 * Definition for Directed graph.
 * struct DirectedGraphNode {
 *     int label;
 *     vector<DirectedGraphNode *> neighbors;
 *     DirectedGraphNode(int x) : label(x) {};
 * };
 */
 
//使用bfs進行拓撲排序:
//1、統計各個節點的入度信息,
//2、查找入度為0的點放入隊列和返回的vector中初始化bfs的隊列
//3、進行bfs,將從隊列中彈出的元素的neighbors的入度減1然後判斷該節點入度是否為0.為0
//   則加入隊列同時加入返回vector中(這一步的主要框架就是bfs的程序框架)
class Solution {
public:

    vector<DirectedGraphNode*> topSort(vector<DirectedGraphNode*> graph) {
        // write your code here
        //1、得到所有節點的入度信息
        map<DirectedGraphNode*, int> indegree = getIndegree(graph);
        
        //2、將入度為0的放入隊列
        
        return addQueue(indegree, graph);
        
    }
    
    map<DirectedGraphNode*, int> getIndegree(vector<DirectedGraphNode*> graph){
        int size = graph.size();
        map<DirectedGraphNode*, int> res;
        if(size == 0){
            return res;
        }
        
        for(int i = 0; i < size; i++){
            DirectedGraphNode* temp = graph[i];
             if(res.find(temp) == res.end()){
                    res[temp] = 0;
             }
            int nbSize = temp->neighbors.size();
            for(int i = 0; i < nbSize; i++){
                DirectedGraphNode* nbNode = temp->neighbors[i];
                if(res.find(nbNode) == res.end()){
                    res[nbNode] = 1;
                    continue;
                }
                res[nbNode]++;
            }
        }
        return res;
    }
    
    vector<DirectedGraphNode*> addQueue(map<DirectedGraphNode*, int>& indegree,vector<DirectedGraphNode*>& graph){
        vector<DirectedGraphNode*> res;
        if(graph.size() == 0){
            return res;
        }
        
        queue<DirectedGraphNode*> nodeQueue;
        //找到一個入度為0的點
        for(auto it = indegree.begin(); it != indegree.end(); ++it){
            if(it->second == 0){
                nodeQueue.push(it->first);
                res.push_back(it->first);
            }
        }
        
        while(nodeQueue.empty() != true){
            DirectedGraphNode* temp = nodeQueue.front();
            nodeQueue.pop();
            int nbSize = temp->neighbors.size();
            for(int i = 0; i < nbSize; i++){
                indegree[temp->neighbors[i]]--;
                if(indegree[temp->neighbors[i]] == 0){
                    nodeQueue.push(temp->neighbors[i]);
                    res.push_back(temp->neighbors[i]);
                }
            }
        }
        
        return res;
        
    }
};

topo sort