算法分析:我是否正确分析了这些算法?如何解决这些问题

时间:2012-07-13 19:29:00

标签: c++ algorithm big-o time-complexity

1)

  x = 25;
    for (int i = 0; i < myArray.length; i++)
    {
        if (myArray[i] == x)
            System.out.println("found!");
    }

我认为这个是O(n)。

2)

for (int r = 0; r < 10000; r++)
    for (int c = 0; c < 10000; c++)
        if (c % r == 0)
            System.out.println("blah!");

我认为这个是O(1),因为对于任何输入n,它将运行10000 * 10000次。不确定这是否正确。

3)

a = 0
for (int i = 0; i < k; i++)
{
    for (int j = 0; j < i; j++)
        a++;
}

我认为这个是O(i * k)。我真的不知道如何处理这样的问题,其中内部循环受到外部循环中递增的变量的影响。这里的一些重要见解将非常感激。外循环运行k次,内循环运行1 + 2 + 3 + ... + k次。因此,该和应为(k / 2)*(k + 1),其为k ^ 2的阶数。它实际上是O(k ^ 3)吗?这似乎太大了。再一次,不知道如何处理这个问题。

4)

int key = 0;    //key may be any value
int first = 0;
int last = intArray.length-1;;
int mid = 0;
boolean found = false;

while( (!found) && (first <= last) )
{
    mid = (first + last) / 2;

    if(key == intArray[mid]) 
        found = true;
    if(key < intArray[mid])
        last = mid - 1;
    if(key > intArray[mid]) 
        first = mid + 1;
}

这个,我认为是O(log n)。但是,我得出了这个结论,因为我相信它是一个二进制搜索,我从阅读中知道运行时是O(log n)。我认为这是因为你为循环的每次迭代将输入大小除以2。但是,我不知道这是否是正确的推理或如何处理我尚未见过的类似算法,并能够推断出它们以更加可验证或正式的方式在对数时间内运行。

5)

int currentMinIndex = 0;

for (int front = 0; front < intArray.length; front++)
{
    currentMinIndex = front;

    for (int i = front; i < intArray.length; i++)
    {
        if (intArray[i] < intArray[currentMinIndex])
        {
            currentMinIndex = i;
        }
    }

    int tmp = intArray[front];
    intArray[front] = intArray[currentMinIndex];
    intArray[currentMinIndex] = tmp;
}

我对此感到困惑。外循环运行n次。并且内部for循环运行 n +(n-1)+(n-2)+ ...(n - k)+ 1次? O(n ^ 3)??

3 个答案:

答案 0 :(得分:2)

或多或少,是的。

1是正确的 - 似乎您正在搜索我认为是未排序集合的特定元素。如果是这样,最坏的情况是元素位于列表的最后,因此O(n)。

2是正确的,虽然有点奇怪。假设rc是常量而且边界​​不是变量,则为O(1)。如果它们是常数,那么是O(1)因为没有什么可输入。

3我相信这仍被认为是O(n ^ 2)。会有一些常数因素,如k * n ^ 2,丢弃常数,你得到O(n ^ 2)。

4看起来很像排序集合的二进制搜索算法。 O(logn)是正确的。它是日志,因为在每次迭代中,您基本上将要查找的元素的可能选择的数量减半。

5看起来像冒泡排序,O(n ^ 2),原因与3相似。

答案 1 :(得分:1)

O()本身并不意味着什么:您需要指定是否计算“最坏情况”O或平均情况O.对于某些排序算法,它们具有O(n log n) )在最坏的情况下平均但是O(n ^ 2)。

基本上你需要计算最内部循环的迭代总数,并且在没有任何常数的情况下取结果的最大分量(例如,如果你有k *(k + 1)/ 2 = 1/2 k ^ 2 + 1/2 k,最大的成分是1/2 k ^ 2因此你是O(k ^ 2))。

例如,你的项目4)在O(log(n))中,因为如果你处理一个大小为n的数组,那么你将在这个数组上运行一次迭代,下一个将在数组上大小为n / 2,然后是n / 4,...,直到这个大小达到1.所以它是log(n)次迭代。

答案 2 :(得分:1)

你的问题主要是关于O()的定义。

当有人说这个算法是O(log(n))时,你必须阅读:

当输入参数n变得非常大时,算法执行的操作数最多会在log(n)中增长

现在,这意味着两件事:

  1. 您必须至少有一个输入参数n。谈论O()没有一个(如你的情况2)是没有意义的。
  2. 您需要定义您正在计算的操作。这些可以是添加,两个元素之间的比较,分配的字节数,函数调用的数量,但您必须决定。通常你会采取对你来说成本最高的操作,或者如果做得太多则会成本高昂的操作。
  3. 所以记住这一点,回到你的问题:

    1. n是myArray.Length,您计算的操作数是'=='。在这种情况下,答案恰好是n,即O(n)

    2. 您无法指定n

    3. n只能是k,你计算的操作数是++。你有k *(k + 1)/ 2,就像你说的那样是O(n2)

    4. 这次n再次是你的数组的长度,你计算的操作是==。在这种情况下,操作的数量取决于数据,通常我们会谈论“最坏情况”,这意味着所有可能的结果,我们看一下花费最多时间的那个。充其量,该算法进行一次比较。在最糟糕的情况下,让我们举一个例子。如果数组是[[1,2,3,4,5,6,7,8,9]]并且你正在寻找4,你的intArray [mid]会连续变为5,3和4,所以你会做3次比较。实际上,对于大小为2 ^ k + 1的数组,最大比较数为k(您可以检查)。所以n = 2 ^ k + 1 =&gt; k = ln(n-1)/ ln(2)。你可以将这个结果扩展到n不是= 2 ^ k + 1时的情况,你会得到复杂度= O(ln(n))

    5. 无论如何,我认为你很困惑,因为你并不确切知道O(n)的含义。我希望这是一个开始。