计算任何方法的运行时复杂度的最佳方法是什么?对于非递归方法,例如bubblesort
,这很容易做到outer-for loop
{
inner-for loop
{
compare and exchange
}
}
要检查,最好的方法是在最里面的循环中放置一个计数器。但是,当该方法是递归的时,我应该在哪里放置计数器,例如合并排序,
sort(int[] array){
left = first-half
right = second-half
sort(left);
sort(right);
ret merge(left, right);
}
merge(int[] left, right)
{
count = length(left + right);
int[] result;
loop-count-times
{
compare and put in result;
}
return result;
}
由于这是合并排序,大(o)是o(n log n),因此100个int的数组应该返回200的big-o。柜台在哪里?如果我把它放在排序(..)的顶部,我得到平均250,280,300,这应该是错的。这个柜台最好的地方是什么?
的引用:http://en.wikipedia.org/wiki/Mergesort
感谢。
答案 0 :(得分:2)
由于这是合并排序,大(o)是o(n log n),因此100个int的数组应该返回200的big-o。
甚至没有接近右边。
使用大型Ordo-notation表示的计算复杂度不告诉您将执行多少步骤/计算操作。有一个原因,它被称为渐近而不是相同的复杂性:它只给你一个接近(更确切地说,给出更高的界限)算法运行时间的函数< strong>关于输入的大小。
所以O(n log n)
并不意味着对于100个元素,将执行200个操作(顺便说一下,对数的基数必须是10?),它告诉您,如果增加输入的大小,(平均情况下)运行时间将与添加的输入数据的数量成比例,乘以此附加数据的对数。
要点:如果你想计算递归函数的调用次数,你应该将计数器作为参数,如下所示:
void merge_sort(int array[], size_t length, int *counter)
{
(*counter)++;
// apply the algorithm to `array`:
merge_sort(array, length, counter);
}
并将其称为:
int num_calls = 0;
merge_sort(array, sizeof(array) / sizeof(array[0]), &num_calls);
printf("Called %d times\n", num_calls);
答案 1 :(得分:1)
我认为你略微误解了Big-O符号的概念。如果复杂度为O(n log n)且n的值为100,则没有严格的规则,程序应该在200的Big-O中完全执行。它只给出了一个上限。例如,考虑具有O(n 2 )复杂度的选择排序。即使n为100,如果列表已经排序,内部循环内的计数器设置也不会给出100 2 。所以在你的情况下,你得到的答案(250,280,300等)是完全有效的。因为所有答案都受k次n log n的限制,其中k是任意常数。