Java 大O分析中方法调用和返回语句的成本是多少?

Java 大O分析中方法调用和返回语句的成本是多少?,java,algorithm,complexity-theory,Java,Algorithm,Complexity Theory,我刚开始学习算法分析,当涉及到方法调用和返回语句的成本时,似乎出现了歧义。一些消息来源对它们的统计与其他不同,因此我希望对此做出一些澄清。以我编写的用于计算最大子阵列的算法(取自伪代码)为例: 我对该算法的初步分析得出: T(n)=8(n-1)+9 =8n-8+9 =8n+1=O(n) 我知道最终结果仍然是O(n),但在这里,我计算: M[t] = max(0, M[t - 1] + array[t]); 分配的成本为2(n-1),(n-1),方法调用的成本为(n-1)。我没有计算最后的ret

我刚开始学习算法分析,当涉及到方法调用和返回语句的成本时,似乎出现了歧义。一些消息来源对它们的统计与其他不同,因此我希望对此做出一些澄清。以我编写的用于计算最大子阵列的算法(取自伪代码)为例:

我对该算法的初步分析得出:

T(n)=8(n-1)+9

=8n-8+9

=8n+1=O(n)

我知道最终结果仍然是O(n),但在这里,我计算:

M[t] = max(0, M[t - 1] + array[t]);
分配的成本为2(n-1),(n-1),方法调用的成本为(n-1)。我没有计算最后的return语句

这似乎是一个相当准确的分析吗?我是否应该将方法调用计算为超过成本1*(n-1)以及最后的返回语句;DR

调用一个方法是O(1),执行它的主体取决于该方法,从方法返回的是O(1)。所以总的来说,重要的是方法体的Big-O(只要这不是或多或少不可能的O(0))

详细解释

方法调用(从调用方的角度看)由三部分组成:

  • 将控件和参数传输到被调用的方法。由于Java在将实例或数组内容作为图形传递之前不会复制它们,所以每个参数的时间都是恒定的,所以对于固定参数列表,总体时间也是恒定的。这里有O(1)。如果要将复杂的表达式作为参数传递,请在方法调用之外对其进行计数
  • 执行方法体(包括任何复杂的返回表达式)。这当然取决于方法。你的
    max(a,b)
    方法没有循环,所以它也是常数时间:O(1)
  • 返回一些值。同样,Java不复制可能导致可变时间的内容,所以它是常量时间:O(1)
您可能会问,将控件转换为无参数方法是否需要与具有10个参数的方法相同的时间。假设1用于准备和执行方法调用,1用于传递单个参数。第一种情况是1,第二种情况是11。但对于大O,11与1相同(两者都是常数),因此结果是O(1)。

TL;DR

调用一个方法是O(1),执行它的主体取决于该方法,从方法返回的是O(1)。所以总的来说,重要的是方法体的Big-O(只要这不是或多或少不可能的O(0))

详细解释

方法调用(从调用方的角度看)由三部分组成:

  • 将控件和参数传输到被调用的方法。由于Java在将实例或数组内容作为图形传递之前不会复制它们,所以每个参数的时间都是恒定的,所以对于固定参数列表,总体时间也是恒定的。这里有O(1)。如果要将复杂的表达式作为参数传递,请在方法调用之外对其进行计数
  • 执行方法体(包括任何复杂的返回表达式)。这当然取决于方法。你的
    max(a,b)
    方法没有循环,所以它也是常数时间:O(1)
  • 返回一些值。同样,Java不复制可能导致可变时间的内容,所以它是常量时间:O(1)

您可能会问,将控件转换为无参数方法是否需要与具有10个参数的方法相同的时间。假设1用于准备和执行方法调用,1用于传递单个参数。第一种情况是1,第二种情况是11。但是对于Big-O,11和1是一样的(两者都是常数),所以结果是O(1)。

我已经有一段时间没有正式研究过Big-O了,但是你想要得到“大”操作,那些实际上需要时间的操作。通常,这一切都是平均的,慢操作和快操作没有太大区别。我要么将方法调用及其返回计数为1个操作,要么根本不计算。然而,基于内存访问和缓存,现代系统具有不同的操作速度,这些差异可能非常显著。如果要进行大量深度嵌套调用,则所需时间可能是一个简单运算符所需时间的10到100倍。另外,关于您的问题,特别是关于
max
,大多数现代JVM内联方法,如果它们小于64字节(字节码)因此,对于这样一个非常短的方法,我会将开销计算为0:它应该完全内联,并且不需要额外的时间。方法调用和返回语句本身是常量因子,可以忽略。代码中的一些注释:与其注释变量的含义,不如这样命名。您的
M
数组可以声明为
int
而不是
Integer
,从而提高性能。根据Java惯例,像
M
这样的局部变量应该以小写字母开头。
M
数组可以声明为
int
,而不是
Integer
M
声明为数组是不必要的。对于当代Java/Java在函数编码方面的尝试,请参见。我已经有一段时间没有正式研究过大O了,但是您希望得到“大”操作,这些操作实际上需要时间。通常,这一切都是平均的,慢操作和快操作没有太大区别。我要么将方法调用及其返回计数为1个操作,要么根本不计算。然而,基于内存访问和缓存,现代系统具有不同的操作速度,这些差异可能非常显著。如果要进行大量的深度嵌套调用,则所需时间可能是一个简单运算符所需时间的10到100倍。另外,关于您的问题,特别是关于
max
,大多数现代JVM内联方法如果小于64字节(字节码),那么对于这样一个非常短的方法,我会计算过多
//method to calculate the max for maxSubFastest
    public static int max(int a, int b)
    {
        return a > b ? a:b;
    }
M[t] = max(0, M[t - 1] + array[t]);