嵌套循环的大O表示法

时间:2016-10-30 08:33:21

标签: algorithm big-o complexity-theory

我正在努力寻找此代码的时间复杂性。

for (int i = 0; i <= n - 1; i++)
  for (int j = i + 1; j <= n - 1; j++)
    for (int k = j + 1; k <= n - 1; k++)

我的尝试: 我们可以用以下形式编写这个循环:

for (int i = 1; i <= n; i++)
  for (int j = 1; j <= n; j++)
    for (int k = 1; k <= n; k++)

现在这个循环的大哦是O(n ^ 5)。我纠正还是做错了?

4 个答案:

答案 0 :(得分:4)

添加了计数器的代码的第一个变体:

int count = 0
for (int i = 0; i <= n - 1; i++)
    for (int j = i + 1; j <= n - 1; j++)
        for (int k = j + 1; k <= n - 1; k++)
            count++;

这计算(i,j,k)的每个组合,其中 0&lt; = i&lt; j&lt; k&lt; Ñ。这对应于您可以从 n 元素中选择3个元素的方式,而不考虑它们的顺序。该号码有a formula

n(n-1)(n-2)/ 3! = n 3 / 6 - n 2 / 2 - n / 2

第二种变体:

int count = 0
for (int i = 0; i <= n - 1; i++)
    for (int j = 0; j <= n - 1; j++)
        for (int k = 0; k <= n - 1; k++)
            count++;

...计算您可以从 n 项目中选择3的方式,但订单很重要,并且允许在3个选项中重复。这个数字很容易导出,因为 i,j,k 是独立的,每个都可以得到 n 不同的值,所以总数是:

n 3

现在它们代表了同样的时间复杂性:

O(n 3 / 6 - n 2 / 2 - n / 2)= O(n 3 )< / em>的

这是因为properties of big O

  

如果函数可能被 n 中的多项式所限制,那么当 n 趋于无穷大时,可以忽略多项式的低阶项。

  

乘以常数
  设 k 为常数。然后:
   O(kg)= O(g)如果 k 非零。

答案 1 :(得分:1)

  

现在这个循环的大哦是O(n ^ 5)。我纠正还是做错了?

不,这不正确。复杂性为O(n^3)

简单来说,你可以这样想:

0开始,到达n-1步骤为1的每个for循环中执行的最大步骤为n。因此,如果您有两个循环,一个嵌套在另一个循环中,那么对于您在外部循环中创建的每个步骤,您将在嵌套循环中执行n个步骤。鉴于您将在外循环中执行的步骤为n,很明显,最后您将执行n^2步骤。

基于以上所述,您可以在以下情况下轻松绘制:

for(int i=0; i<=n-1; i++)
{
    for(int j=0; j<=n-1; j++)
    {
        for(int k=0; k<=n-1; k++)
        {

        }
    }
}

您将执行n^3步骤。因此复杂性大约为O(n^3)

答案 2 :(得分:1)

这些循环是否嵌套?如果是这样,那么你就可以重新编写循环,以便更容易理解。虽然我会给每个循环一个不同的迭代器名称,以避免混淆:

for (int a = 1; a <= n; a++) {
    for (int b = 1; b <= n; b++) {
        for (int c = 1; c <= n; c++) {
            ...
        }
    }
}

实际上,您可以将这些变量重命名为任何您想要更容易推理的变量。怎么样:

for (int street = 1; street <= n; street++) {
    for (int house = 1; house <= n; house++) {
        for (int room = 1; room <= n; room++) {
            ...
        }
    }
}

现在,问题变成了,如果我必须访问n个城市的n个房间的n个房间,我需要访问多少个房间?

希望你能看到答案是n * n * n,即n ^ 3。

获得答案的快捷方式是看到你有3个嵌套for循环从1到n,所以答案是n ^ 3.

答案 3 :(得分:0)

如果您有疑问,并且想要说服自己只是进行一些测试:

#include <stdio.h>

int main()
{
int count1=0,count2=0;
int n=100;

for (int i = 0; i <= n - 1; i++)

for (int j = i + 1; j <= n - 1; j++)

for (int k = j + 1; k <= n - 1; k++)
  count1++;

for (int i = 1; i <= n; i++)

for (int j = 1; j <= n; j++)

for (int k = 1; k <= n; k++)
  count2++;

printf("count1 %d count2 %d n %d\n",count1,count2,n);
return 0;
}

结果:

count1 161700 count2 1000000 n 100
  • 显然,第二个循环运行100**3次=&gt;为O(n ** 3)

  • 第一个循环由于边界而运行较少,但它仍然是线性的(在边界上没有除法运算)=&gt; O(n ** 3)即使它更快也是如此。