下面代码的最坏情况复杂性

时间:2015-04-06 20:32:51

标签: java algorithm heap

所以我一般都是Java和编码的新手,刚学过Big-O。我昨天在互联网上遇到过这个问题(http://www.dsalgo.com/2013/02/MaxKUsingMinHeap.php.html),想知道下面的代码的复杂性分析[O(n log k)]是否正确。它是否也包括最坏的情况?如果有人可以通过这个并解释,我真的很感激。

import java.util.PriorityQueue;

public class MaxKUsingMinHeap {
    public static void main(String[] args) {
        int[] arr = { 
            3, 46, 2, 56, 3, 38, 93, 45, 6, 787, 34, 76, 44, 6, 7, 86, 8, 44, 56 
        };
        int[] result = getTopElements(arr, 5);
        for (int i : result) {
            System.out.print(i + ",");
        }
    }
    public static int[] getTopElements(int[] arr, int k) {
        PriorityQueue<Integer> minHeap = new PriorityQueue<Integer>();
        for (int i = 0; i < arr.length; ++i) {
            int currentNum = arr[i];
            if (minHeap.size() < k) {
                minHeap.add(currentNum);
            }
            else if (currentNum > minHeap.peek())
            {
                minHeap.poll();
                minHeap.add(currentNum);
            }
        }
        int[] result = new int[minHeap.size()];
        int index = 0;
        while (!minHeap.isEmpty()) {
            result[index++] = minHeap.poll();
        }
        return result;
    }
}

2 个答案:

答案 0 :(得分:2)

是的,无论如何,该代码永远不会超过O(n log k),因为优先级队列操作每个都需要O(log k),并且您最多只能执行O(n)。< / p>

答案 1 :(得分:0)

您提供的程序的渐近复杂性详细信息取决于PriorityQueue实现的详细信息,并且未记录这些详细信息。但是,假设对于每种方法执行的操作数(无论是平均情况还是最差情况),实现都是最优

(constructor)       O(1)
size()              O(1)
add()               O(log(k))
peek()              O(1)
poll()              O(log(k))
isEmpty()           O(1)

其中k是队列中当前元素的数量。特别是,这些是由“堆”数据结构支持的队列的特征,变量命名似乎假定为实现(并且它是一个非常合理的假设)。

现在考虑方法getTopElements(int[] arr, int k),让n成为arr.length。方法:

  • PriorityQueue操作
  • 中分配并初始化O(1)
  • n arr元素进行迭代,在每次迭代时产生以下费用:
    • O(1) operations
    • 中将数组中的值复制到局部变量
    • 确定是否将当前数字添加到队列中,如果是,则首先删除最少元素。 决定依赖于size()peek()方法以及个别比较,因此需要O(1)次操作。
    • 如果添加了该号码,则这样做的成本受O(log k)限制,因为队列中的元素数量不会超过k。如果首先删除元素,则删除的成本也是O(log k)操作。从O(log k) + O(log k) = O(log k)开始,渐近的复杂性并没有因为有时需要先删除一个元素而增加。
  • 然后,该方法为结果分配一个数组,代价为O(1)次。
  • 它在队列上迭代min(n, k)次(每个元素一次),每次都以O(log k)为界的成本删除元素。

对于第一个循环,成本受n * (O(1) + O(1) + O(log k)) = n * O(log k) = O(n log k)限制。对于第二个循环,它由min(n, k) * O(log k) = O(n log k)限定(我们也可以将其缩小为O(k log k),因为big-O是上限; O(min(n, k))是{ {1}} O(n))。总的来说,该方法需要O(k)次操作。

除了该操作之外,main方法还分配一个O(n log k) + O(n log k) = O(n log k) - 元素数组(n),初始化其成员(O(1)),并迭代结果,打印每个( O(n))。这些成本都不超过O(k)方法的成本,因此方法的成本占总成本的主导地位。