我正在阅读一篇关于比较两种算法的文章,首先分析它们。
我的老师告诉我,您可以直接使用该算法的步骤数来分析算法。
代表:
algo printArray(arr[n]){
for(int i=0;i<n;i++){
write arr[i];
}
}
的复杂度为O(N)
,其中N
是数组的大小。并且它会重复N
次的for循环。
而
algo printMatrix(arr,m,n){
for(i=0;i<m;i++){
for(j=0;j<n;j++){
write arr[i][j];
}
}
}
O(MXN)
时,会有O(N^2)
〜M=N
的复杂程度。 for
内的语句执行MXN
次。
同样O(log N)
。如果它将输入分成两个相等的部分。等等。
但根据那篇文章:
措施Execution Time
,Number of statements
不适合分析算法。
,因为:
Execution Time
将是系统相关的,
Number of statements
会因使用的编程语言而异。
并说明
理想解决方案将表示算法的运行时间作为N
的输入大小f(n)
的函数。
让我感到困惑的是,如果你把执行时间视为不好的措施,你如何计算运行时间?
专家可以请详细说明吗?
提前致谢。
答案 0 :(得分:2)
执行时间确实取决于系统,但它还取决于算法执行的指令数。
另外,我不明白步骤的数量是多么无关,因为算法被分析为与语言无关,并且没有注意各种语言所暗示的任何特征和语法 - 糖。
自从我开始分析算法以来,始终遇到的算法分析的一个衡量标准是执行指令的数量,我无法看到该指标可能无关紧要。
与此同时,复杂性类别意味着&#34;数量级&#34;表明算法有多快或多慢。它们取决于执行的指令的数量和算法运行的系统的独立,因为根据定义,基本操作(例如添加两个数字)应该花费恒定的时间,无论大小&#34;恒定&#34;在实践中意味着复杂性类别不会改变。精确复杂度函数的表达式中的常量可能确实因系统而异,但实际上与算法比较相关的是复杂性类,因为只有比较那些才能找出算法在上的行为越来越大与其他算法相比,输入(渐近)。
答案 1 :(得分:2)
Big-O表示法会消除常数(固定成本和常数乘数)。因此,无论kn+c
和O(n)
如何,任何需要k
操作完成的函数(根据定义!)c
。这就是为什么通过真实数据对您的算法进行实际测量(分析)通常会更好,以了解它们实际有多快。
但显然,执行时间会因数据集的不同而有所不同 - 如果您尝试根据具体情况提出 的一般衡量标准使用场景,那么执行时间就不那么有价值了(除非您在相同条件下比较所有算法,即使这样,除非您对大多数可能的场景建模,而不仅仅是一个,否则它不一定是公平的)。
当你转向更大的数据集时,Big-O符号变得更有价值。它可以让您大致了解算法的性能,假设k
和c
的值合理。如果您想要排序一百万个数字,那么可以肯定地说您希望远离任何O(n^2)
算法,并尝试找到更好的O(n lg n)
算法。如果你对三个数字进行排序,那么理论上的复杂性就不再重要了,因为这些常数在所采用的资源中占主导地位。
另请注意,尽管在编程语言之间可以表达给定算法的语句数量变化很大,但需要执行的常量时间步数(在目标体系结构的机器级别,通常是一个)其中整数算术和内存访问需要一段固定的时间,或者更确切地说,有界一段固定的时间。这就是大O测量算法所需的最大固定成本步数,它与给定输入的实际运行时间没有直接关系,但仍大致描述了工作
答案 2 :(得分:2)
当您说“O(N)的复杂性”时,称为“Big-O表示法”,与您在帖子中提到的“理想解决方案”相同。它是一种将运行时表示为输入大小的函数。
我认为当你说“表达运行时间”时你感到困惑 - 它并不意味着用数值表示它(这是执行时间),它意味着用Big-O表示法表达它。我想你刚刚在术语上被绊倒了。
答案 3 :(得分:2)
在比较算法时,执行速度很重要,其他人也提到过,但其他因素如内存空间也很重要。
内存空间也使用复杂符号的顺序。
代码可以使用仅需要少量额外内存O(1)的冒泡排序对数组进行排序。其他方法虽然速度较快,但可能需要O(ln N)内存。
其他更深奥的措施包括代码复杂性,如Cyclomatic complexity和Readability
答案 4 :(得分:1)
传统上,计算机科学使用&#34; Big O表示法&#34;来衡量算法有效性(速度)的比较次数或有时数据访问次数。之所以这样,是因为比较(和/或数据访问)的数量是描述某些算法效率的一个很好的数学模型,特别是搜索和排序算法,其中O(log n)在理论上被认为是最快的。 / p>
这个理论模型总是有几个缺陷。它假设比较(和/或数据访问)需要花费时间,并且执行函数调用和分支/循环等操作的时间是可以忽略的。这在现实世界中当然是无稽之谈。
在现实世界中,与快速和快速相比,递归二进制搜索算法可能是非常慢的。使用plain for循环实现脏线性搜索,因为在给定系统上,函数调用开销是花费最多时间的,而不是比较。
有许多因素会影响性能。随着CPU的发展,发明了更多这样的东西。如今,您可能需要考虑数据对齐,指令管道,分支预测,数据高速缓存,多CPU核心等内容。所有这些技术都使传统的算法理论变得无关紧要。
要编写最有效的代码,您需要考虑特定的系统,并且需要深入了解所述系统。幸运的是,编译器也进化了很多,所以很多深入的系统知识可以留给为特定系统实现编译器端口的人。
一般来说,我认为今天许多程序员花费了太多时间来思考程序速度并提出了“聪明的东西”#34;获得更好的表现。回到CPU速度慢且编译器很糟糕的时代,这些事情非常重要。但是今天,一个优秀的,现代的程序员专注于使代码无错误,可读,可维护,可重用,安全,可移植等等。如果程序有多快,那么这个程序的速度并不重要。难以理解的垃圾。因此,在需要时处理性能。