代码之家  ›  专栏  ›  技术社区  ›  Margus

如何在创建调度程序时避免无限循环

  •  5
  • Margus  · 技术社区  · 15 年前

    我得到了如何制作物品的食谱。配方的格式为: {element that is being crafter}: {list of elements, that is needed} x ,我需要知道如何制作它的元素。所以我想知道我学菜谱的顺序。

    对于有效的输入,如以下所有操作都有效:

    // Input:
    { 
        "F1: F2 F3 F4", "F5: F6 F4", "F6: F7 F8 F4", "F2: F3 F8 F4", "F8: F4",
        "F9: F4", "F7: F4", "F10: F7 F4", "F11: F4", "F4:", "F3: F6"
    }
    // Output:
    [F4, F7, F8, F6, F3, F2, F1, F5, F9, F10, F11]
    

    { "F1: F2", "F2: F1" } .

    mp 包含配方名称作为键,元素作为值, labels 是独一无二的 mp公司 result 将包含答案。我在找一个归路 empty 如果满足无限循环,则返回结果。

    private void getArray(HashMap<String, ArrayList<String>> mp,
            ArrayList<String> result, ArrayList<String> labels) {
        for (String a : labels) {
            if (mp.get(a) != null)
                for (String label : mp.get(a))
                    getArray(mp, result, label);
            if (!result.contains(a))
                result.add(a);
        }
    }
    
    private void getArray(HashMap<String, ArrayList<String>> mp,
            ArrayList<String> result, String label) {
        if (result.contains(label))
            return;
        if (mp.get(label) == null) {
            result.add(label);
            return;
        }
        for (String l : mp.get(label))
            getArray(mp, result, l);
        if (!result.contains(label))
            result.add(label);
    }
    

    问题解决了。

    /** <p>
     * <b>Topological sort</b> solves a problem of - finding a linear ordering
     * of the vertices of <i>V</i> such that for each edge <i>(i, j) ∈ E</i>,
     * vertex <i>i</i> is to the left of vertex <i>j</i>. (Skiena 2008, p. 481)
     * </p>
     * 
     * <p>
     * Method is derived from of <a
     * href="http://en.wikipedia.org/wiki/Topological_sort#Algorithms" > Kahn's
     * pseudo code</a> and traverses over vertices as they are returned by input
     * map. Leaf nodes can have null or empty values. This method assumes, that
     * input is valid DAG, so if cyclic dependency is detected, error is thrown.
     * tSortFix is a fix to remove self dependencies and add missing leaf nodes.
     * </p>
     * 
     * <pre>
     * // For input with elements:
     * { F1=[F2, F3, F4], F10=[F7, F4], F11=[F4], F2=[F3, F8, F4], F3=[F6], 
     *   F4=null, F5=[F6, F4], F6=[F7, F8, F4], F7=[F4], F8=[F4], F9=[F4]}
     *   
     * // Output based on input map type: 
     * HashMap: [F4, F11, F8, F9, F7, F10, F6, F5, F3, F2, F1]
     * TreeMap: [F4, F11, F7, F8, F9, F10, F6, F3, F5, F2, F1]
     * </pre>
     * 
     * @param g
     *            <a href="http://en.wikipedia.org/wiki/Directed_acyclic_graph"
     *            > Directed Acyclic Graph</a>, where vertices are stored as
     *            {@link java.util.HashMap HashMap} elements.
     * 
     * @return Linear ordering of input nodes.
     * @throws Exception
     *             Thrown when cyclic dependency is detected, error message also
     *             contains elements in cycle.
     * 
     */
    public static <T> ArrayList<T> tSort(java.util.Map<T, ArrayList<T>> g)
            throws Exception
    /**
     * @param L
     *            Answer.
     * @param S
     *            Not visited leaf vertices.
     * @param V
     *            Visited vertices.
     * @param P
     *            Defined vertices.
     * @param n
     *            Current element.
     */
    {
        java.util.ArrayList<T> L = new ArrayList<T>(g.size());
        java.util.Queue<T> S = new java.util.concurrent.LinkedBlockingDeque<T>();
        java.util.HashSet<T> V = new java.util.HashSet<T>(), 
        P = new java.util.HashSet<T>();
        P.addAll(g.keySet());
        T n;
    
        // Find leaf nodes.
        for (T t : P)
            if (g.get(t) == null || g.get(t).isEmpty())
                S.add(t);
    
        // Visit all leaf nodes. Build result from vertices, that are visited
        // for the first time. Add vertices to not visited leaf vertices S, if
        // it contains current element n an all of it's values are visited.
        while (!S.isEmpty()) {
            if (V.add(n = S.poll()))
                L.add(n);
            for (T t : g.keySet())
                if (g.get(t) != null && !g.get(t).isEmpty() && !V.contains(t)
                        && V.containsAll(g.get(t)))
                    S.add(t);
        }
    
        // Return result.
        if (L.containsAll(P))
            return L;
    
        // Throw exception.
        StringBuilder sb = new StringBuilder(
                "\nInvalid DAG: a cyclic dependency detected :\n");
        for (T t : P)
            if (!L.contains(t))
                sb.append(t).append(" ");
        throw new Exception(sb.append("\n").toString());
    }
    
    /**
     * Method removes self dependencies and adds missing leaf nodes.
     * 
     * @param g
     *            <a href="http://en.wikipedia.org/wiki/Directed_acyclic_graph"
     *            > Directed Acyclic Graph</a>, where vertices are stored as
     *            {@link java.util.HashMap HashMap} elements.
     */
    public static <T> void tSortFix(java.util.Map<T, ArrayList<T>> g) {
        java.util.ArrayList<T> tmp;
        java.util.HashSet<T> P = new java.util.HashSet<T>();
        P.addAll(g.keySet());
    
        for (T t : P)
            if (g.get(t) != null || !g.get(t).isEmpty()) {
                (tmp = g.get(t)).remove(t);
                for (T m : tmp)
                    if (!P.contains(m))
                        g.put(m, new ArrayList<T>(0));
            }
    }
    
    2 回复  |  直到 15 年前
        1
  •  10
  •   Gareth Rees    15 年前

    你要解决的问题是 topological sort . Kahn's algorithm 解决了这个问题,同时也检测到无效的输入(即,包含循环)。

        2
  •  3
  •   Andrzej Doyle    15 年前

    这样做的快速方法是记住已经看到的一组项,如果您要为列表中已经存在的项计算需求,则只需抛出一个异常。这肯定会表明某种圆度,我们可能认为这是件坏事。

    Future 弹出地图以指示评估可能尚未完成。然后,只要访问给定的项,就可以在地图中添加“解决方案占位符”。因此,无限循环可以正常工作(查看您的无效情况):

    1. 参观F1。在地图上写下未来。递归求出F2。

    这当然表示解决方案的对象模型中的循环,但这实际上是输入的合法表示。如果您以图形方式显示它,可能是以一次展开一个级别的树的形式显示,那么它也会适当地呈现(“如何创建F1?你需要做一个二楼。如何创建 那个 ? 当用户展开树时,您需要创建一个F1“,以此类推。

    错误的 输入。)