📜  通过简单的示例了解时间复杂性

📅  最后修改于: 2021-05-08 17:13:35             🧑  作者: Mango

很多学生在理解时间复杂性的概念时会感到困惑,但是在本文中,我们将用一个非常简单的示例来解释它:
想象一下一个教室,有100个学生,您在其中将钢笔交给了一个人。现在,您想要那支笔。以下是一些查找笔的方法以及O顺序是什么。
O(n 2 ):你去问班上的第一人,如果他有钢笔。另外,您问这个人关于教室中其他99个人是否有钢笔之类的东西,
这就是我们所说的O(n 2 )。
O(n):去问每个学生分别是O(N)。
O(log n):现在我将课堂分为两组,然后问:“是在教室的左侧还是右侧?”然后,我将那个小组分成两部分,然后再次询问,依此类推。重复此过程,直到剩下一个拥有笔的学生。这就是O(log n)的意思。
如果只有一个学生知道笔藏在哪个学生身上,我可能需要进行O(n 2 )搜索。如果一个学生有笔并且只有他们知道,我会使用O(n)。如果所有学生都知道,我会使用O(log n)搜索,但是只有在我猜对了的情况下才告诉我。

注意:我们对程序执行期间相对于输入的时间增长率感兴趣。

另一个例子:
算法/代码的时间复杂度等于执行特定代码所需的实际时间,而是语句执行的次数。我们可以通过使用time命令来证明这一点。例如,用C / C++或任何其他语言编写代码以查找N个数字之间的最大值,其中N在10、100、1000、10000之间变化。然后使用以下命令在基于Linux的操作系统(Fedora或Ubuntu)上编译该代码:

gcc program.c – o program
run it with time ./program

您会得到令人惊讶的结果,即对于N = 10,您可能会得到0.5毫秒的时间,对于N = 10,000,您可能会得到0.2毫秒的时间。另外,您将在不同的计算机上获得不同的时间。因此,可以说执行代码所需的实际时间取决于计算机(无论您使用的是pentium1还是pentiun5),并且如果您的计算机位于LAN / WAN中,它还会考虑网络负载。即使您在同一台机器上使用相同的代码也不会获得相同的时间,这是当前网络负载的原因。
现在,如果时间复杂度不是执行代码所需的实际时间,那么就会出现问题,那是什么呢?

答案是:我们没有考虑执行代码中每个语句所需的实际时间,而是考虑每个语句执行多少次。
例如:

C
#include 
int main()
{
    printf("Hello World");
}


C
#include 
void main()
{
    int i, n = 8;
    for (i = 1; i <= n; i++) {
        printf("Hello Word !!!\n");
    }
}


C
Pseudocode:
Sum(a,b){
return a+b  //Takes 2 unit of time(constant) one for arithmetic operation and one for return.(as per above conventions)   cost=2 no of times=1
}


C
Pseudocode:
list_Sum(A,n){//A->array and n->number of elements in the array
total =0           // cost=1  no of times=1
for i=0 to n-1     // cost=2  no of times=n+1 (+1 for the end false condition)
sum = sum + A[i]   // cost=2  no of times=n
return sum         // cost=1  no of times=1
}


输出
Hello World

在上面的代码“ Hello World !!!”中在屏幕上仅打印一次。因此,时间复杂度是恒定的:O(1),即,无论您使用的是哪种操作系统或机器配置,每次执行代码所需的时间都是恒定的。

现在考虑另一个代码:

C

#include 
void main()
{
    int i, n = 8;
    for (i = 1; i <= n; i++) {
        printf("Hello Word !!!\n");
    }
}
输出
Hello Word !!!
Hello Word !!!
Hello Word !!!
Hello Word !!!
Hello Word !!!
Hello Word !!!
Hello Word !!!
Hello Word !!!

在上面的代码“ Hello World !!!”中将打印N次。因此,上述代码的时间复杂度为O(N)。
资料来源:Reddit

附加信息 :
例如:
让我们考虑具有以下规格的模型机:
–单处理器
–32位
–顺序执行
–1单位时间的算术和逻辑运算
–1单位时间用于赋值和返回语句

1. 2个数字之和:

C

Pseudocode:
Sum(a,b){
return a+b  //Takes 2 unit of time(constant) one for arithmetic operation and one for return.(as per above conventions)   cost=2 no of times=1
}

Tsum = 2 = C = O(1)

2.列表中所有元素的总和:

C

Pseudocode:
list_Sum(A,n){//A->array and n->number of elements in the array
total =0           // cost=1  no of times=1
for i=0 to n-1     // cost=2  no of times=n+1 (+1 for the end false condition)
sum = sum + A[i]   // cost=2  no of times=n
return sum         // cost=1  no of times=1
}        

Tsum = 1 + 2 *(n + 1)+ 2 * n + 1 = 4n + 4 = C1 * n + C2 = O(n)

3.矩阵所有元素的总和:

对于这一点,复杂度是一个多项式方程(方矩阵的二次方程)
矩阵nxn => Tsum = an 2 + bn + c
对于此Tsum,如果按n 2 = O(n 2 )的顺序
上面的代码不是伪代码,并且不类似于任何编程语言,因此无法在IDE中运行。
因此,从以上我们可以得出结论,执行时间会随着我们使用输入进行的操作类型的增加而增加。
上面的O->被称为Big – Oh,这是一个渐近符号。还有其他渐近符号,例如theta和Ohm。

如何比较算法?

为了比较算法,让我们定义一些客观的度量:

  • 执行时间:这不是一个很好的衡量标准,因为执行时间是特定于特定计算机的。
  • 执行的语句数量:这不是一个很好的衡量标准,因为语句的数量随编程语言和各个程序员的风格而变化。
  • 理想的解决方案:让我们假设,我们对表达特定的算法的运行时间为输入大小为n(即F(N))的函数,将对应于运行时间,这些不同的功能。这种比较与机器时间,编程风格等无关。

您可以参考:了解渐近符号 
本文提供的其他信息是Pathange Balaji Rao。