public List<T> topologicalSort() {
            // inDegree represents the amount of edges coming into each node
            Map<T, Integer> inDegree = new HashMap<T, Integer>();
            for (T node : nodes)
                inDegree.put(node, 0);

            for (T node : edges.keySet()) {
                for (T neighbour : edges.get(node)) {
                    inDegree.put(neighbour, inDegree.get(neighbour) + 1);
                }
            }

            Queue<T> queue = new LinkedList<T>();
            for (T node : nodes)
                if (inDegree.get(node) == 0)
                    queue.add(node);

            /*
             * Gradually remove nodes that have no incoming edges; remove all edges
             * starting in the removed node, and add all nodes that now have in-degree
             * 0 to the queue.
             */
            List<T> result = new ArrayList<T>();
            while (!queue.isEmpty()) {
                T node = queue.poll();
                result.add(node);

                if (!edges.containsKey(node))
                    continue;

                for (T neighbour : edges.get(node)) {
                    int degree = inDegree.get(neighbour);
                    --degree;
                    if (degree == 0)
                        queue.add(neighbour);
                    inDegree.put(neighbour, degree);
                }
            }

            return result;
        }