Topological Sort

Build the Topological Sequence

Use node to build the dependency. You can also use map or other data structure.

class Node {
    int val;
    Set<Node> next; //current node has higher priority than next
    Node(int val) {
        this.val = val;
        next = new HashSet<>();
    }
}
public List<Node> topologicalSort(Set<Node> nodeSet) {
    Set<Node> visited = new HashSet<>();
    List<Node> ls = new LinkedList<>();
    for(Node n: nodeSet) helper(visited,n,ls);
    return ls;
}

private void helper(Set<Node> visited, Node root, List<Node> ls) {
    if(visited.contains(n)) return;
    visited.add(root);
    for(Node n: root.next) {        
        helper(visited,n,ls);
    }
    ls.add(0,root); // or add to end and reverse the final result in topologicalSort
}

Detect if a graph is a Directed Acyclic Graph (DAG):

DFS Solution

public boolean checkTopologicalSort(Set<Node> nodeSet) {
    Set<Node> visited = new HashSet<>();
    for(Node n: nodeSet) {
        if(!helper(visited,n,new HashSet<>())) return false;
    }
    return true;
}

private boolean helper(Set<Node> visited, Node root, Set<Node> checking) {
    if(checking.contains(n)) return false;
    if(visited.contains(n)) return true;
    visited.add(root);
    checking.add(root);
    for(Node n: root.next) {
        if(!helper(visited,n,checking)) return false;
    }
    checking.remove(root); // CAUTION: Remember to add this line!
    return true;
}

BFS Solution (unchecked)

Use in degree.

public boolean checkTopologicalSort(Set<Node> nodeSet) {
    Set<Node> visited = new HashSet<>();
    Map<Node,Integer> indegree = new HashMap<>();
    Deque<Node> dq = new ArrayDeque<>();
    List<Node> sequence = new ArrayList<>();
    // compute indegree of each node
    for(Node n: nodeSet) indegree.put(m,0);     
    for(Node n: nodeSet) {
        if(n.next!=null) for(Node m: n.next) {
            indegree.put(m,indegree.get(m)+1);
        }
    }
    //add node with indegree 0
    for(Node n: indegree.keySet()) {
        if(indegree.get(n)==0) dq.add(n);
    }
    // BFS
    while(!dq.isEmpty()) {
        int size = dq.size();
        for(int i=0;i<size;i++) {
            Node curNode = dq.pollFirst();
            sequence.add(curNode);
            if(curNode.next!=null) for(node n:curNode.next) {
                int in = indegree.get(n);
                indegree.put(n,in-1);
                if(indegree.get(n)==0) dq.add(n);
            }
        }
    }
    return sequence.size()==nodeSet.size();
    // and we can print the priority from List sequence
}

Output all possible sequence (tested)

int dfs(unordered_set<int>& visited, unordered_map<int, vector<int>>& g, int cur, unordered_set<int>& curLine, unordered_map<int, int>& node2lvl) {
    // if (curLine.find(cur)!=curLine.end()) 
    //     return;
    // curLine.insert(cur);
    if (visited.find(cur)!=visited.end())
        return node2lvl[cur];
    visited.insert(cur);
    int lvl = 0;
    for (int nxt: g[cur]) {
        lvl = max(lvl, dfs(visited, g, nxt, curLine, node2lvl)+1);
    }
    // curLine.erase(cur);
    node2lvl[cur] = lvl;
    return lvl;
}

vector<vector<int>> generate_sequences(int cur_lvl, unordered_map<int, vector<int>>& lvl2nodes) {
    vector<vector<int>> ret;
    if (lvl2nodes.find(cur_lvl)==lvl2nodes.end())
        return ret;

    int nxt_lvl = cur_lvl+1;
    auto& comb = lvl2nodes[cur_lvl];
    sort(comb.begin(), comb.end());
    do {
        auto tmp = generate_sequences(nxt_lvl, lvl2nodes);
        if (tmp.size()==0) {
            ret.pu sh_back({});
            auto& ref = ret.back();
            ref.insert(ref.end(), comb.begin(), comb.end());
        } else {
            for (auto v: tmp) {
                ret.push_back({});
                auto& ref = ret.back();
                ref.insert(ref.end(), comb.begin(), comb.end());
                ref.insert(ref.end(), v.begin(), v.end());
            }
        }

    } while(next_permutation(comb.begin(), comb.end()));

    return ret;
}


vector<vector<int>> topologicalSort(unordered_map<int, vector<int>>& g) {
    unordered_set<int> visited;
    unordered_set<int> curLine; // detect the circle

    unordered_set<int> allNode;
    // collect all the node number
    for (auto [n, nxt_v]: g) {
        allNode.insert(n);
        for (auto nxt: nxt_v) {
            allNode.insert(nxt);
        }
    }

    // compute depth lvl first using topological sort
    unordered_map<int, int> node2lvl;
    for (auto n: allNode) {
        // curLine.clear();
        dfs(visited, g, n, curLine, node2lvl);
    }

    // generate all possible sequence based on the lvl
    unordered_map<int, vector<int>> lvl2nodes;
    for (auto [n, l]: node2lvl)
        lvl2nodes[l].push_back(n);

    vector<vector<int>> ret;
    ret = generate_sequences(0, lvl2nodes);
    return ret;
}

Last updated