directedacyclicgraph.java

来自「JAVA图论的算法包。用过觉得还不错」· Java 代码 · 共 1,200 行 · 第 1/3 页

JAVA
1,200
字号
     * detection
     *
     * @throws CycleFoundException if a cycle is discovered
     */
    private void dfsF(
        V vertex,
        Set<V> df,
        Visited visited,
        Region affectedRegion)
        throws CycleFoundException
    {
        int topoIndex = topoOrderMap.getTopologicalIndex(vertex);

        // Assumption: vertex is in the AR and so it will be in visited
        visited.setVisited(topoIndex);

        df.add(vertex);

        for (E outEdge : outgoingEdgesOf(vertex)) {
            V nextVertex = getEdgeTarget(outEdge);
            Integer nextVertexTopoIndex =
                topoOrderMap.getTopologicalIndex(nextVertex);

            if (nextVertexTopoIndex.intValue() == affectedRegion.finish) {
                // reset visited
                try {
                    for (V visitedVertex : df) {
                        visited.clearVisited(
                            topoOrderMap.getTopologicalIndex(visitedVertex));
                    }
                } catch (UnsupportedOperationException e) {
                    // okay, fine, some implementations (ones that automatically
                    // clear themselves out) don't work this way
                }
                throw new CycleFoundException();
            }

            // note, order of checks is important as we need to make sure the
            // vertex is in the affected region before we check its visited
            // status (otherwise we will be causing an
            // ArrayIndexOutOfBoundsException).
            if (affectedRegion.isIn(nextVertexTopoIndex)
                && !visited.getVisited(nextVertexTopoIndex))
            {
                dfsF(nextVertex, df, visited, affectedRegion); // recurse
            }
        }
    }

    /**
     * Depth first search backward, building up the set (db) of back-connected
     * vertices in the Affected Region
     *
     * @param vertex the vertex being visited
     * @param db the set we are populating with back-connected vertices in the
     * AR
     * @param visited
     * @param topoIndexMap
     */
    private void dfsB(
        V vertex,
        Set<V> db,
        Visited visited,
        Region affectedRegion)
    {
        // Assumption: vertex is in the AR and so we will get a topoIndex from
        // the map
        int topoIndex = topoOrderMap.getTopologicalIndex(vertex);
        visited.setVisited(topoIndex);

        db.add(vertex);

        for (E inEdge : incomingEdgesOf(vertex)) {
            V previousVertex = getEdgeSource(inEdge);
            Integer previousVertexTopoIndex =
                topoOrderMap.getTopologicalIndex(previousVertex);

            // note, order of checks is important as we need to make sure the
            // vertex is in the affected region before we check its visited
            // status (otherwise we will be causing an
            // ArrayIndexOutOfBoundsException).
            if (affectedRegion.isIn(previousVertexTopoIndex)
                && !visited.getVisited(previousVertexTopoIndex))
            {
                // if prevousVertexTopoIndex != null, the vertex is in the
                // Affected Region according to our topoIndexMap

                dfsB(previousVertex, db, visited, affectedRegion);
            }
        }
    }

    @SuppressWarnings("unchecked")
    private void reorder(Set<V> df, Set<V> db, Visited visited)
    {
        List<V> topoDf = new ArrayList<V>(df);
        List<V> topoDb = new ArrayList<V>(db);

        Collections.sort(topoDf, topoComparator);
        Collections.sort(topoDb, topoComparator);

        // merge these suckers together in topo order

        SortedSet<Integer> availableTopoIndices = new TreeSet<Integer>();

        // we have to cast to the generic type, can't do "new V[size]" in java
        // 5;
        V [] bigL = (V []) new Object[df.size() + db.size()];
        int lIndex = 0; // this index is used for the sole purpose of pushing
                        // into

        // the correct index of bigL

        // assume (for now) that we are resetting visited
        boolean clearVisited = true;

        for (V vertex : topoDb) {
            Integer topoIndex = topoOrderMap.getTopologicalIndex(vertex);

            // add the available indices to the set
            availableTopoIndices.add(topoIndex);

            bigL[lIndex++] = vertex;

            if (clearVisited) { // reset visited status if supported
                try {
                    visited.clearVisited(topoIndex);
                } catch (UnsupportedOperationException e) {
                    clearVisited = false;
                }
            }
        }

        for (V vertex : topoDf) {
            Integer topoIndex = topoOrderMap.getTopologicalIndex(vertex);

            // add the available indices to the set
            availableTopoIndices.add(topoIndex);
            bigL[lIndex++] = vertex;

            if (clearVisited) { // reset visited status if supported
                try {
                    visited.clearVisited(topoIndex);
                } catch (UnsupportedOperationException e) {
                    clearVisited = false;
                }
            }
        }

        lIndex = 0; // reusing lIndex
        for (Integer topoIndex : availableTopoIndices) {
            // assign the indexes to the elements of bigL in order
            V vertex = bigL[lIndex++]; // note the post-increment
            topoOrderMap.putVertex(topoIndex, vertex);
        }
    }

    //~ Inner Interfaces -------------------------------------------------------

    /**
     * For performance tuning, an interface for storing the topological ordering
     *
     * @author gilesp
     */
    public interface TopoOrderMapping<V>
        extends Serializable
    {
        /**
         * add a vertex at the given topological index.
         *
         * @param index
         * @param vertex
         */
        public void putVertex(Integer index, V vertex);

        /**
         * get the vertex at the given topological index.
         *
         * @param index
         *
         * @return
         */
        public V getVertex(Integer index);

        /**
         * get the topological index of the given vertex.
         *
         * @param vertex
         *
         * @return the index that the vertex is at, or null if the vertex isn't
         * in the topological ordering
         */
        public Integer getTopologicalIndex(V vertex);

        /**
         * remove the given vertex from the topological ordering
         *
         * @param vertex
         *
         * @return the index that the vertex was at, or null if the vertex
         * wasn't in the topological ordering
         */
        public Integer removeVertex(V vertex);

        /**
         * remove all vertices from the topological ordering
         */
        public void removeAllVertices();
    }

    public interface TopoOrderMappingFactory<V>
    {
        public TopoOrderMapping<V> getTopoOrderMapping();
    }

    /**
     * this interface allows specification of a strategy for marking vertices as
     * visited (based on their topological index, so the vertex type isn't part
     * of the interface).
     */
    public interface Visited
    {
        /**
         * mark the given topological index as visited
         *
         * @param index the topological index
         */
        public void setVisited(int index);

        /**
         * has the given topological index been visited?
         *
         * @param index the topological index
         */
        public boolean getVisited(int index);

        /**
         * Clear the visited state of the given topological index
         *
         * @param index
         *
         * @throws UnsupportedOperationException if the implementation doesn't
         * support (or doesn't need) clearance. For example, if the factory
         * vends a new instance every time, it is a waste of cycles to clear the
         * state after the search of the Affected Region is done, so an
         * UnsupportedOperationException *should* be thrown.
         */
        public void clearVisited(int index)
            throws UnsupportedOperationException;
    }

    /**
     * interface for a factory that vends Visited implementations
     *
     * @author gilesp
     */
    public interface VisitedFactory
        extends Serializable
    {
        public Visited getInstance(Region affectedRegion);
    }

    //~ Inner Classes ----------------------------------------------------------

    /**
     * Note, this is a lazy and incomplete implementation, with assumptions that
     * inputs are in the given topoIndexMap
     *
     * @param <V>
     *
     * @author gilesp
     */
    private static class TopoComparator<V>
        implements Comparator<V>,
            Serializable
    {
        /**
         */
        private static final long serialVersionUID = 1L;

        private TopoOrderMapping<V> topoOrderMap;

        public TopoComparator(TopoOrderMapping<V> topoOrderMap)
        {
            this.topoOrderMap = topoOrderMap;
        }

        public int compare(V o1, V o2)
        {
            return topoOrderMap.getTopologicalIndex(o1).compareTo(
                topoOrderMap.getTopologicalIndex(o2));
        }
    }

    /**
     * a dual HashMap implementation
     *
     * @author gilesp
     */
    private class TopoVertexBiMap
        implements TopoOrderMapping<V>,
            TopoOrderMappingFactory<V>
    {
        /**
         */
        private static final long serialVersionUID = 1L;

        private final Map<Integer, V> topoToVertex = new HashMap<Integer, V>();
        private final Map<V, Integer> vertexToTopo = new HashMap<V, Integer>();

        public void putVertex(Integer index, V vertex)
        {
            topoToVertex.put(index, vertex);
            vertexToTopo.put(vertex, index);
        }

        public V getVertex(Integer index)
        {
            return topoToVertex.get(index);
        }

        public Integer getTopologicalIndex(V vertex)
        {
            Integer topoIndex = vertexToTopo.get(vertex);
            return topoIndex;
        }

        public Integer removeVertex(V vertex)
        {
            Integer topoIndex = vertexToTopo.remove(vertex);
            if (topoIndex != null) {
                topoToVertex.remove(topoIndex);
            }
            return topoIndex;
        }

        public void removeAllVertices()
        {
            vertexToTopo.clear();
            topoToVertex.clear();
        }

        public TopoOrderMapping<V> getTopoOrderMapping()
        {
            return this;
        }
    }

    /**
     * For performance and flexibility uses an ArrayList for topological index
     * to vertex mapping, and a HashMap for vertex to topological index mapping.
     *
     * @author gilesp
     */
    public class TopoVertexMap
        implements TopoOrderMapping<V>,
            TopoOrderMappingFactory<V>
    {
        /**
         */
        private static final long serialVersionUID = 1L;

        private final List<V> topoToVertex = new ArrayList<V>();
        private final Map<V, Integer> vertexToTopo = new HashMap<V, Integer>();

        public void putVertex(Integer index, V vertex)
        {
            int translatedIndex = translateIndex(index);

            // grow topoToVertex as needed to accommodate elements
            while ((translatedIndex + 1) > topoToVertex.size()) {
                topoToVertex.add(null);
            }

            topoToVertex.set(translatedIndex, vertex);
            vertexToTopo.put(vertex, index);
        }

        public V getVertex(Integer index)
        {
            return topoToVertex.get(translateIndex(index));
        }

        public Integer getTopologicalIndex(V vertex)
        {
            return vertexToTopo.get(vertex);
        }

        public Integer removeVertex(V vertex)
        {
            Integer topoIndex = vertexToTopo.remove(vertex);
            if (topoIndex != null) {
                topoToVertex.set(translateIndex(topoIndex), null);
            }
            return topoIndex;
        }

        public void removeAllVertices()
        {
            vertexToTopo.clear();

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?