按节点具有的子节点数量对无序树进行排序

时间:2017-04-15 21:42:45

标签: java sorting tree stack-overflow

我目前正在研究" Java中的算法"罗伯特·塞奇威克(Robert Sedgewick)(第3版,德文版)我自己正在尝试解决其中一个练习,目前来自"创意解决方案" -section。

作为一个练习解决方案的一部分,我尝试按每个节点所拥有的子节点数量对未排序的树进行排序,首先有大量子节点的节点:

  1. 根据子节点本身具有的子节点nNodes的数量对父节点n0的所有子节点进行排序,从左到右从最大到最小排序。对树中的所有节点执行此排序。
  2. 如果这些子节点的2个兄弟节点n1和n2具有相同的nNodes,则转到n1的子节点,并且n2尝试根据它们最大的nNodes对这两个子节点进行排序儿童。如果没有找到差异,请尝试根据其第二大孩子的nNodes等进行排序。
  3. 如果您的孩子用尽,请转到2岁孩子的子节点,孩子数量最多,重复2次等。
  4. 如果经过所有比较后发现n1和n2都是具有相同形状的树的根,那么两者中的哪一个先出现并不重要。
  5. 为了进行视觉比较,这个"规则"将导致如下所示的以​​下树排序:Example of Sorting

    代码

    我遇到的问题是正确实施排序。每棵树都由节点组成。每个节点都包含一个值(因此您有一个"名称"对于节点,对于排序本身并不重要,它只关心每个节点拥有的子节点数)和一个节点的数组列表引用该节点的子节点。对于没有子节点的节点,ArrayList的大小为0.这里的关键是对所有节点中的ArrayLists进行排序,我目前正在尝试使用带有Comparator对象的内置排序方法。我想我必须递归地接近这个,这使整个事情变得非常混乱,因为我现在有一个比较器方法调用自己,同时也调用" sort"对于其他ArraLists采用相同的方法。下面的sortForest方法在我尝试使用某些主要方法进行测试时,会给出堆栈溢出错误。

        static NodeComparator comp = new NodeComparator();
    
        static class Node {
            int value;
            ArrayList<Node> children;
    
            Node(int value, ArrayList<Node> children) {
                this.value = value;
                this.children = children;
            }
        }
    
        static class NodeComparator implements Comparator<Node> {
            public NodeComparator() {
            }
    
            public int compare(Node n1, Node n2) {
                /*-
                 * Base Case 1: Both Nodes are leafs (isEmpty() is true) - they are
                 * equal -> return 0.
                 * Base Case 2/3: One of the Nodes is a leaf while the other isn't - 
                 * the one that is a leaf is "lower" than the one that isn't. ->
                 * return (-) 1. 
                 */
                if (n1.children.isEmpty() && n2.children.isEmpty()) {
                    return 0;
                } else if (n2.children.isEmpty()) {
                    n1.children.sort(comp);
                    return 1;
                } else if (n1.children.isEmpty()) {
                    n2.children.sort(comp);
                    return -1;
                } else {
                    /* Get the amount of children the 2 nodes n1 and n2 have */
                    int nChildren1 = (n1.children.isEmpty()) ? 0 : n1.children.size();
                    int nChildren2 = (n2.children.isEmpty()) ? 0 : n2.children.size();
                    /* Always sort the ArrayList of children that they have */
                    n1.children.sort(comp);
                    n2.children.sort(comp);
    
                    /*
                     * If n1 and n2 have equal amounts of children, compare the
                     * amounts of children their children have, from largest to
                     * lowest
                     */
                    if (nChildren1 == nChildren2) {
                        int result = 0;
                        for (int i = 0; (i < nChildren1) && (result == 0); i++) {
                            compare(n1.children.get(i), n2.children.get(i));
                        }
                        return result;
                    } else {
                        /*- If one node has more children than the other, sort accordingly */
                        return ((nChildren1 > nChildren2) ? 1 : -1);
                    }
                }
            }
        }
    
        static void sortForest(Node root) {
            for (int i = 0; i < root.children.size(); i++) {
                sortForest(root.children.get(i));
                root.children.sort(comp);
            }
            return;
        }
    

    问题

    如何让这段代码生效?我有点确定这大致是一个正确解决方案的大概,但我已经尝试过几个小时来考虑这个并且无法弄清楚。我确信这会给我堆栈溢出,因为某处有一个永无止境的递归,我只是没有看到它。一般来说,递归给我带来了在精神上正确地做到这一点的问题。我无法找到相同的问题,那些类似的问题与二叉树而不是无序树有关。

2 个答案:

答案 0 :(得分:0)

根据树的大小,在调用sortForest时可能会遇到有关Java默认堆栈大小的限制。它的方法包括通过-Xss JVM选项增加它,在Thread constructor中设置堆栈大小,以非递归方式重写它或使用Trampoline pattern。< / p>

答案 1 :(得分:0)

上述代码有几个问题:

  1. 代码假设每棵树的根节点都没有包含对自身的引用(上面的代码中没有显示),这最初导致compare方法一次又一次地调用root,这已得到纠正。

  2. 在比较方法中调用排序是绝对不必要的,也是错误的。代码已经从每个具有sortForest()的节点调用排序方法,从叶子开始,因此没有位置,需要从比较方法的代码的所有部分中删除。

    < / LI>
  3. 对于给定的返回,compare方法不会导致从最大到最小,但从最小到最大的排序。它需要返回1,返回-1,反之亦然。

  4. 比较方法在其for循环中还需要将compare()的返回值存储在result中,否则结果永远不会改变,并且一旦不相似,循环就不会停止已被发现。

  5. root.children.sort(comp);绝对sortForest()的排序必须发生在forLoop之外,否则你会对其中的某些ArrayList进行排序为了正确执行所有通话。

  6. 在纠正所有这些后,上面的sortForest()compare()方法提供了正确的排序结果,例如:

    int[] tree1 = { 2, 3, 3, 3, 2, 2, 1, 0, 7, 5, 3, 10, 10, 6 };

    int[] tree2 = { 4, 10, 11, 0, 4, 0, 12, 4, 7, 8, 0, 3, 4, 12 };

    this picture所示对其进行排序。

    可以找到解决方案的完整代码以及一些优化和删除不必要的代码以及使用固定排序here