所以我一般都是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;
}
}
答案 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)
方法的成本,因此方法的成本占总成本的主导地位。