【问题标题】:Time complexity of a function with while loops and an if statement带有 while 循环和 if 语句的函数的时间复杂度
【发布时间】:2018-11-18 03:43:48
【问题描述】:
int dup_chk(int a[], int length) 
{
  int i = length;
  while (i > 0)
  {
    i--;
    int j = i -1;
    while (j >= 0)
    {
      if (a[i] == a[j])
      {
        return 1;
      }
      j--;
    }
  }
  return 0;
}

所以我认为我知道以下内容:

  • 第 1 行只是 1。
  • 第一个 while 循环是 N+1。
  • 我——;自第一个 while 循环以来是 N 次。
  • j = i -1;也是 N。
  • 第二个 while 循环是 (N+1)N = N^2+N,因为它是 while 循环中的一个 while 循环
  • if 语句:???
  • j--;是 N(N) = N^2
  • 返回0;是 1

我对计算算法的时间复杂度真的很陌生,所以我什至不确定我认为我知道的是否完全正确。 但困扰我的是 if 语句,我不知道如何计算(如果后面还有 else 怎么办?)

编辑:总计等于 3/2N^2 + 5/2N+3 我知道这个函数是 O(N^2),但不太明白总计是如何计算的。

【问题讨论】:

  • Big-O 分析是关于渐近性能的。如果数组中的任何两个条目相同,则算法会提前退出。如果所有值都是唯一的,则为 O(N²),因为每个值都与其他值进行比较。 N ⟶ ∞ 的渐近情况可以忽略恒定成本,甚至 O(N) 成本,因为 O(N²) 成本占主导地位。这就是 Big-O 符号的美丽和简单。
  • 您能详细说明一下吗?我有点失落。我知道这个函数是 O(N^2),因为当 N 非常大时,其余的无关紧要,但我不太明白如何计算确切的总数。编辑:总数应该是 3/2N^2 + 5/2N+3 只是我不确定这个总数是如何达到的。 (我也会在主要问题中对此进行编辑)
  • 您可能会感兴趣许多不同的行为:例如,最佳、最差和平均情况。由于if 会导致过早退出,因此最坏的情况当然if 永远不会成立。有许多算法的平均情况与最坏情况有很大不同。
  • 我认为我正在寻找的是一个悲观的绩效衡量标准。最坏的情况。
  • 这里的关键是算法理论和“Big O”大多是 1960 年代的 BS。在现实世界中唯一重要的是代码的执行速度,它以秒为单位,而不是“n”。比较相对便宜。在旧的废话编译器上,由于“如果为零则分支”指令,向下迭代会产生稍快的比较。那是 1980 年代至 1990 年代的某个地方。 今天重要的是分支的数量和迭代数据的一致性。因此,对所有数据进行线性搜索可能比对某些数据进行二分搜索快几倍。

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


【解决方案1】:

if 检查的执行次数与内部 while 循环的迭代次数一样多。

return 1 根据定义最多只执行一次。您似乎假设输入中没有重复项(即最坏的情况),在这种情况下,return 1 语句永远不会执行。

您最终会了解可以忽略代码的哪些部分,因此您不需要计算这个“总计”,只需意识到有两个嵌套循环,每个循环都遍历数组 - 即。 O(N^2)。

【讨论】:

  • 我有点想知道这个总数是如何达到的,尽管我知道知道它是没有用的,因为它显然是 O(N^2)
  • @Khaled :loudmummer 的回答给出了彻底的分析,所以您可能对此感兴趣。
【解决方案2】:

也许这可以帮助您了解代码中出了什么问题。我添加了一些打印输出,以便更容易理解代码中发生的情况。我认为这应该足以找到您的错误

int dup_chk(int a[], int length)
{
    int j = 0;
    int i = length;
    char stringa[30];

    printf("Before first while loop j = %d and i = %d \n", j, i);
    while (i > 0)
    {
        i--;
    j = i - 1;
    printf("\tIn first while loop j = %d and i = %d\n", j, i);
    while (j >= 0)
    {
        printf("\t\tIn second while loop j = %d and i = %d\n", j, i);
        if (a[i] == a[j])
        {
            printf("\t\tIn if statment j = %d and i = %d\n", j, i);
            return 1;
        }
        j--;
        printf("\t\tEnd of second while loop j = %d and i = %d\n", j, i);
    }
}
printf("After first while loop j = %d and i = %d \n", j, i);
printf("Press any key to finish the program and close the window\n");
return 0;
}

我还应该建议调试你的代码,了解发生了什么更好。

【讨论】:

  • 据我所知,代码中没有任何错误。所有这些打印语句都是多余的。
【解决方案3】:
int dup_chk(int a[], int length) 
{
  int i = length;
  while (i > 0)  // Outer loop
  {
    i--;
    int j = i -1;
    while (j >= 0)  // Inner loop
    {
      if (a[i] == a[j])
      {
        return 1;
      }
      j--;
    }
  }
  return 0;
}

上面的程序正是你的代码,我冒昧添加了两个 cmets。

让我们考虑最坏的情况(因为这是每个人都关心/担心的)。如果你仔细观察,你会发现对于i 的每个值,Inner loop 都会执行i - 1 次。因此,如果您的Outer loop 执行n 次,则Inner loop 将总共执行n * (n - 1) 次(即n - 1 每次n 的值)。

n * (n - 1) 在一般代数中产生n^2 - n。现在,n^2 随着您继续增加n 的值而突飞猛进(与n 相比)。渐近符号让我们考虑对要执行的步骤数影响最大的因素。因此,我们可以忽略n,并说这个程序的最坏情况运行时间为 O(n^2)。

这就是 Big-O 符号的美丽和简单。 - 引用上面 cmets 中的 Jonathan Leffler。

【讨论】:

  • 我不太确定为什么内部循环会执行 n*(n-1) 次而不是 n*(n+1) 次,因为当 j 为时,while 条件又执行了一次
  • @Khaled j 的值将是 1 小于 j 就在 Inner loop 的开头。
【解决方案4】:

通常不需要对时间复杂度进行如此准确的分析。就 Big-O 而言,了解它就足够了。不过,出于自己的好奇心,我做了一些计算。

如果您关心的只是获取时间复杂度的最坏情况分析,请考虑仅包含唯一元素的数组。在这种情况下:

  • return 1 语句从不执行。内部 while 循环执行 N(N-1)/2 次(从 1 到 N 求和 i-1),并发生三件事 - 检查 while 条件(并评估为真),if 条件是检查(并评估为假)和变量j 递减。因此,操作次数为 3N(N-1)/2。
  • 外层while循环执行N次,除了条件检查外还有三个语句——i递减,j赋值,内层while条件失败N次。那是 4N 次以上的操作。
  • 在所有循环之外,还有另外三个语句。初始化iwhile条件失败一次,然后返回语句。在我们的计数中再增加 3 个。

3/2N2 - 3/2N + 4N + 3。

这是 3/2N2 + 5/2N + 3。这是你的“总和”。

重复一遍,这个计算对于所有实际目的都是完全没有必要的。

【讨论】:

    【解决方案5】:

    全面评估:

    这个程序有一个特殊的功能:如果找到一对相等值的(a[I], a[J]),它就会终止。假设我们知道IJ(我们稍后会看到如果没有这样的对会怎样)。

    外部循环对所有I <= i < L 执行,因此L-I 次。每次,内部循环对所有0 <= j < i 执行,因此i 次,除了最后一次(i = I):我们有J <= j < I 因此I-J 迭代。

    我们假设循环的“成本”是a N + b 的形式,其中a 是单次迭代的成本,b 是一些固定开销。

    现在对于内部循环,它运行L-I 次,迭代次数减少,使用“三角数”公式,成本为

    a (L-1 + L-2 + ... I+1 + I-J) + b (L - I) = a ((L-1)L/2 - I(I+1)/2 + I-J) + b (L-I)
    

    我们将外部循环的成本添加到其中

    a ((L-1)L/2 - I(I+1)/2 + I-J) + b (L-I) + c
    

    (其中b 是与上述不同的常数)。

    一般来说,这个函数在L中是二次的,但是如果很快找到一对(比如I = L-3),它就变成线性的;在最好的情况下(I = L-1,J = L-2),它甚至是常量a + b + c

    最坏的情况发生在最后找到配对时(I = 1J = 0),这实际上相当于没有找到配对。然后我们有

    a (L-1)L/2 + b (L - 1) + c
    

    显然是O(L²)

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-02-13
      • 2022-01-26
      • 2012-12-02
      • 1970-01-01
      • 2013-12-08
      相关资源
      最近更新 更多