ID photo of Ciro Santilli taken in 2013 right eyeCiro Santilli OurBigBook logoOurBigBook.com  Sponsor 中国独裁统治 China Dictatorship 新疆改造中心、六四事件、法轮功、郝海东、709大抓捕、2015巴拿马文件 邓家贵、低端人口、西藏骚乱
cpp/topological_sort.cpp
#include <cassert>
#include <list>
#include <unordered_set>
#include <unordered_map>
#include <utility>
#include <vector>

template <class T>
struct Node {
    Node(T n) : dependencies_left(0), n(n) {};
    int dependencies_left;
    T n;
    std::vector<Node*> dependants;
};

template <class T>
std::list<T> topological_sort(const std::vector<std::pair<T,T>>& pairs) {
    std::list<T> ret;
    std::unordered_map<T,Node<T>> n_to_node;
    std::vector<const Node<T>*> nodeps;

    // Initialize graph.
    for (const auto& pair : pairs) {
        // Perfect example of an application of emplace! Because:
        // * we want the storage to live in n_to_node
        // * we don't want to define or call an unecessary default constructor
        auto val1 = pair.first;
        auto& n1 = (n_to_node.emplace(val1, val1).first)->second;
        auto val2 = pair.second;
        auto& n2 = (n_to_node.emplace(val2, val2).first)->second;
        n1.dependants.push_back(&n2);
        n2.dependencies_left++;
    }

    // Initialize and run.
    for (auto& kv : n_to_node) {
        auto& node = kv.second;
        if (node.dependencies_left == 0) {
            nodeps.push_back(&node);
        }
    }
    while (!nodeps.empty()) {
        const auto& cur = nodeps.back();
        nodeps.pop_back();
        ret.push_back(cur->n);
        for (const auto& dependant : cur->dependants) {
            dependant->dependencies_left--;
            if (dependant->dependencies_left == 0)
                nodeps.push_back(dependant);
        }
    }
    return ret;
}

int main() {
    /*
       6        4
       |        |
    +--+--+     v
    |  |  |     7
    v  |  v
    3  |  2-+
    |  |  | |
    |  v  | |
    +->1<-+ |
       |    |
       v    |
       5<<--+
    */
    std::vector<std::pair<int,int>> in{
        {6, 3},
        {6, 2},
        {3, 1},
        {2, 1},
        {6, 1},
        {1, 5},
        {2, 5},
        {4, 7},
    };
    assert((
        topological_sort(in) ==
        std::list{6, 2, 3, 1, 5, 4, 7}
        // Also OK.
        //std::list{6, 4, 3, 2, 7, 1, 5}
    ));
}