跟踪运行时复杂性

时间:2013-03-10 06:22:54

标签: sorting big-o

计算任何方法的运行时复杂度的最佳方法是什么?对于非递归方法,例如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

感谢。

2 个答案:

答案 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是任意常数。