[C++]C++ STL 拓扑排序序列 DFS 逆后序序列

拓扑排序序列

原理

Proposition. A digraph has a topological order if and only if it is a DAG.
Proposition. Reverse postorder in a DAG is a topological sort.

完整源码

#include 
#include  
#include 
#include 
#include 
using namespace std;

int V, E;
//有向图
map<int, vector<int>> G;
bool marked[100];   // v 是否已经被访问过?
queue<int> postorder; // 后序序列

void dfs(int v) {
    marked[v] = true;
    for(vector<int>::iterator ii = G[v].begin(); ii != G[v].end(); ii++) {
        int w = *ii;
        if(!marked[w]) dfs(w);
    }

    postorder.push(v);
}


void topological() {
    for (int v = 0; v < V; v++)
        if (!marked[v]) dfs(v);

    cout << "a topological order : " << endl;
    stack<int> reverse;
    while(!postorder.empty()) {
        reverse.push(postorder.front());
        postorder.pop();
    }

    while(!reverse.empty()) {
        cout << reverse.top() << " ";
        reverse.pop();
    }
}

void readData() {
    cin >> V >> E;
    for(int i = 0 ; i < E ;i++)
    {
        int v, w;
        cin >> v >> w;
        G[v].push_back(w);
    }
}

void showData() {
    cout << "Digraph : " << endl;
    for(int v = 0; v < V; v++) 
    {
        cout << v << " : ";
        for(vector<int>::iterator ii = G[v].begin(); ii != G[v].end(); ii++)
            cout << v << "->" << *ii << " ";
        cout << endl;
    }

    system("pause");
}

int main()
{
    readData();
    showData();

    topological();
}

模拟数据

[C++]C++ STL 拓扑排序序列 DFS 逆后序序列_第1张图片

测试运行

6
6
0 3
3 4
4 5
0 1
1 2
2 4
Digraph :
0 : 0->3 0->1
1 : 1->2
2 : 2->4
3 : 3->4
4 : 4->5
5 :
请按任意键继续. . .
a topological order :
0 1 2 3 4 5
--------------------------------
Process exited after 1.523 seconds with return value 0
请按任意键继续. . .

拓扑排序存在的前提

  • 没有环

后序序列

void dfs(int v) {
    marked[v] = true;
    for(vector<int>::iterator ii = G[v].begin(); ii != G[v].end(); ii++) {
        int w = *ii;
        if(!marked[w]) dfs(w);
    }

    postorder.push(v); //* 放在这里
}
  • postorder 是一个queue,就是放在dfs的最后;

逆后序

void topological() { 

    /* 1.开始DFS搜索 */
    for (int v = 0; v < V; v++)
        if (!marked[v]) dfs(v);

    cout << "a topological order : " << endl;


    /* 2.后序序列压入栈 */
    stack<int> reverse;
    while(!postorder.empty()) {
        reverse.push(postorder.front());
        postorder.pop();
    }


    /* 3.栈再输出就是逆后序了 */
    while(!reverse.empty()) {
        cout << reverse.top() << " ";
        reverse.pop();
    }

}

逆后序不是前序

[C++]C++ STL 拓扑排序序列 DFS 逆后序序列_第2张图片

  • 前序 (中 左 右) : 0 1 2 3 4
  • 后序 (左 右 中 ) :1 3 4 2 0
  • 逆后序 (后序求反) :0 2 4 3 1

逆后序

  1. 没有环,就可以变成树的形式;
  2. 后序序列是往一个队列里去存的,队列是FIFO(先进先出);
  3. DFS是一个递归过程,那么进入这个队列的顶点,左顶点(右顶点)都会比中顶点更先,也就是被指向的顶点会先进入的这个队列;
  4. 拓扑排序的起点是一个入度为零的点,也就是不被任何顶点指向的点,一定是一个中顶点(也就是树里的根),所以只要将后序序列求个反,得到的必然是一串指出的顶点,也就是拓扑序列
  5. 前序序列失效,不能充当拓扑排序序列可以见参考引用[3](或者点我)

引用参考

[1] C++ STL queue
http://www.cplusplus.com/reference/queue/queue/push/

[2] algs4 后序序列 逆后序序列
http://algs4.cs.princeton.edu/42digraph/DepthFirstOrder.java.html

[3]前序序列不能保证找到拓扑排序序列
https://www.zhihu.com/question/28549004/answer/41236788

你可能感兴趣的:(算法(初学),C++)