Java 打印BST的所有路径的时间复杂度是多少

Java 打印BST的所有路径的时间复杂度是多少,java,algorithm,recursion,Java,Algorithm,Recursion,我有这段代码,它与本网站上的其他代码略有不同,但有相同的问题: public void printAllRootToLeafPaths(Node node,ArrayList path) { if(node==null){ return; } path.add(node.data); if(node.left==null && node.right==null) { System.out.println(p

我有这段代码,它与本网站上的其他代码略有不同,但有相同的问题:

public void printAllRootToLeafPaths(Node node,ArrayList path) {
    if(node==null){
        return;
    }
    path.add(node.data);

    if(node.left==null && node.right==null)
    {
        System.out.println(path);
        return;
    }
    else {
        printAllRootToLeafPaths(node.left, new ArrayList(path));
        printAllRootToLeafPaths(node.right,new ArrayList(path));
    }      
}
有人能解释为什么最好的情况是O(nlogn)? 最坏的情况是,树分解为链表,数组被复制1+2+3+…+n-1+n次,相当于n^2,因此时间复杂度为O(n^2)。

沿路径中的每个节点复制最佳情况数组。所以复制它看起来像1+2+3+…+logn。N/2次。那么,如果1+2+3+…+n-1+n是n^2,为什么总和(logn)不是^2呢?最好的情况是O(n(logn)^2)?

我认为您忽略了将整个阵列复制到新阵列的时间复杂性


在根节点:
添加了一个元素,但创建了两个新数组

在根节点的左侧子节点:
添加了一个元素,但使用两个元素创建了两个新数组

。 .

最后只有一个级别:
添加了一个元素,但创建了两个大小为log n的新数组,以2为基数。

在最后一级:添加一个元素,并打印logn元素


因此,在每个节点上,都有一个向列表中添加元素的操作和一个打印或复制大小列表(logh)的操作,其中h是树中节点的高度

因为我们只遍历所有元素一次,所以操作的总数是:
n个加法+Sum(logh1+logh2+logh3+…loghn)

其中h1、h2、h3…hn是每个节点的高度


大约是
n+O(n log n)
~
O(n log n)
是的,所有复制都需要考虑

这些副本不是必需的;编写以下函数很容易:

  • 使用(单个)链接列表代替ArrayList,或
  • 使用单个ArrayList,在不再需要以前的路径时覆盖它们
对于非复制算法,算法的成本是打印路径的成本,即从根到叶的所有路径的长度之和。在每次调用时复制数组,使成本成为从根到每个节点(而不是每个叶)的路径之和。(数组被复制两次的事实与复杂性分析无关;它只意味着乘以一个常数因子,这个常数因子可以忽略。)

对于非复制算法,最佳情况是线性树,每个节点只有一个子节点。然后只有一片叶子的路径长度为N,所以总成本为O(N)。但如果在每个节点上复制,则这是最糟糕的输入;节点路径长度为连续整数,节点路径长度之和为二次

对于您的算法,最佳情况是完全平衡的完全占用树。在一棵完全占用的树中,有一片叶子比没有叶子的节点多;换句话说,大约一半的节点是叶子。在一个完全平衡的树中,每个节点都可以从根节点到达,最多需要logn个步骤。所以每个节点的路径长度之和是O(N logn)。(有些节点更接近,但对于计算大O,我们可以忽略这一事实。即使我们考虑到这一点,我们也会发现它不会改变渐近行为,因为每个深度级别的节点数在每个连续级别上都是双倍的。)因为一半的节点是叶子,所以这个输入的成本是O(N log N)还有非复制算法

这两种算法都表现出最坏情况下的二次复杂度。我们已经看到了复制算法的最坏输入:只有一片叶子的线性树。对于非复制算法,我们使用了非常类似的东西:由左链接主干组成的树,其中每个右链接都是一片叶子:

                         root
                          /\
                         /  \
                        /\   7
                       /  \
                      /\   6
                     /  \
                    /\   5
                   /  \
                  /\   4
                 /  \
                /\   3
               /  \
               1  2

由于该树已被完全占用,其一半节点是叶子,并且它们的距离不断增加,因此这也是二次的(尽管常数乘数较小)。

这是否回答了您的问题?这段代码略有不同,因为该方法每次调用都复制数组。我的印象是复制数组增加了时间复杂性。也就是说,复制数组的代价是O(l)l是数组的长度。因此,对于每个路径中的每个节点,复制数组看起来像1+2+3+…+logn。然而,似乎代码,一次添加整个数组的行为是O(logn)(或者如果打印它,它将是O(logn)。因此我感到困惑。为每个调用复制数组是否不会增加时间复杂度?打印会增加时间复杂度吗?