Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/319.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 算法,大O表示法:这个函数是O(n^2)吗?还是O(n)?_Java_Algorithm_Big O - Fatal编程技术网

Java 算法,大O表示法:这个函数是O(n^2)吗?还是O(n)?

Java 算法,大O表示法:这个函数是O(n^2)吗?还是O(n)?,java,algorithm,big-o,Java,Algorithm,Big O,这是一本算法书中的代码,“Java中的数据结构和算法,第6版”,作者:Michael T.GoodRich、Roberto Tamassia和Michael H.Goldwasser public static String repeat1(char c, int n) { String answer = ""; for(int j=0; j < n; j++) { answer += c; } return answer; }

这是一本算法书中的代码,“Java中的数据结构和算法,第6版”,作者:Michael T.GoodRich、Roberto Tamassia和Michael H.Goldwasser

public static String repeat1(char c, int n)
{
    String answer = "";
    for(int j=0; j < n; j++)
    {
         answer += c;
    }  
    return answer;
}
publicstaticstringrepeat1(字符c,int-n)
{
字符串答案=”;
对于(int j=0;j
根据作者的说法,该算法的大O表示法是O(n^2),原因如下: 命令answer+=c是answer=(answer+c)的简写 命令不会导致将新字符添加到现有字符串中 实例;而是生成一个具有所需序列的新字符串 字符,然后重新分配变量answer,以引用该新变量 就效率而言,这种解释的问题是 连接后创建新字符串需要时间 这与结果字符串的长度成正比 通过此循环,结果的长度为1,第二次通过循环 结果的长度为2,依此类推,直到我们到达长度的最后一个字符串 n、 "

然而,我不明白,这段代码怎么会有O(n^2),因为不管n的值是多少(不包括j语句answer+=c每次迭代都需要两个基本操作,与值n无关,因此我认为这个函数的方程应该是4n+3。(每个回路运行j 或者,是这样一句话,“从效率的角度来看,这种解释的问题是,作为串联的结果,创建一个新字符串需要与结果字符串的长度成比例的时间。”简单地说,作为串联的结果创建一个新字符串需要与其长度成比例的时间,而不管函数中使用了多少基本操作?因此,基本操作的数量对函数的运行时间没有太大影响,因为串联字符串赋值的内置代码t操作员的运行时间以O(n^2)为单位

这个函数怎么可能是O(n^2)


感谢您的支持。

复杂度变为O(n^2)因为每次字符串的长度增加1,并在每次需要
n
复杂度时创建它。此外,外部循环的复杂度为
n
。因此确切的复杂度将为(n*(n+1))/2,即O(n^2)

比如说,

对于
abcdefg

a // one length string object is created so complexity is 1
ab // similarly complexity is 2
abc // complexity 3 here 
abcd // 4 now.
abcde // ans so on.
abcdef
abcedefg

现在,您可以看到总的复杂性是1+2+3+4+…+n=(n*(n+1))/2。在大O表示法中,它是O(n^2)

在循环的每次迭代中,语句
answer+=c;
必须将字符串
answer
中已经存在的每个字符复制到一个新字符串中

例如,n=5,c=5

  • 第一个循环:
    answer
    是一个空字符串,但它仍然必须创建一个新字符串。有一个操作可以附加第一个
    '5'
    ,而
    answer
    现在是
    “5”
  • 第二个循环:
    answer
    现在将指向一个新字符串,将第一个
    '5'
    复制到一个新字符串,并附加另一个
    '5'
    ,以使
    '55
    。不仅创建了一个新的
    字符串
    ,还从上一个字符串复制了一个字符
    '5'
    ,并追加了另一个
    '5'
    。追加了两个字符
  • 第n个循环:
    answer
    现在将指向一个新字符串,将n-1个
    '5'
    字符复制到一个新字符串,并附加一个
    '5'
    字符,以生成一个包含n5的字符串
复制的字符数为1+2+…+n=n(n+1)/2。这是O(n2)


在Java中,在循环中构造这样的字符串的有效方法是使用
StringBuilder
,使用一个可变的对象,并且不需要每次在每个循环中追加一个字符时复制所有字符。使用
StringBuilder
的成本为O(n).

字符串在Java中是不可变的。我认为这段糟糕的代码是O(n^2),正是因为这个原因,而且只有这个原因。每次迭代时它都必须构造一个新字符串。我不确定字符串串联是否与字符数成真正的线性比例(因为字符串的长度已知,所以它似乎应该是一个常数时间操作)。但是,如果您接受作者的说法,然后迭代n次,每次迭代的时间与n成正比,则得到n^2。StringBuilder将为您提供O(n)。

这是因为:

answer += c;
是一个
字符串
串联。在java
中,字符串
不可变的

这意味着连接的字符串是通过创建原始字符串的副本并将
c
附加到它来创建的。因此,对于
n
大小
string
,一个简单的连接操作是
O(n)

在第一次迭代中,答案长度为
0
,在第二次迭代中答案长度为
1
,在第三次迭代中答案长度为2,依此类推

所以你每次都在做这些操作

1 + 2 + 3 + ... + n = O(n^2)

对于字符串操作,
StringBuilder
是首选方法,即它在
O(1)
时间中附加任何字符。

将字符串的长度视为“n”,因此每次我们需要在末尾添加元素,因此字符串的迭代为“n”,并且我们还有外部For循环,因此为“n”,因此我们得到O(n^2).

我基本上同意它在实践中是O(n^2),但考虑到:

Java是聪明的。在许多情况下,它使用StringBuilder而不是string来进行隐藏的连接。你不能假设它每次都要复制底层数组(尽管在这种情况下几乎肯定会)

Java变得越来越智能,这是没有理由的