Space 逐字符添加 Java 字符串的复杂性

Space complexity of adding Java Strings char by char

当通过"addition"循环构建一个Java字符串char by char时,可以观察到执行此操作的时间复杂度为差:是 quadratic O(n^2) 时间。但是,我想知道 space 复杂度 "adding" 一个 String char-by-char 通过循环的复杂性是否也很差。

这是一个最小的程序示例,它通过使用秒表计时的逐字符加法来构建字符串。下面显示的结果清楚地显示了二次曲线:

/**Create a String of n 'A's char-by-char.
 * @param n Number of 'A's to be appended
 * @return The finished string
 */
public static String appendString(int n) {
    String str = "";
    // Timed run starts here
    long t = System.currentTimeMillis();
    // String concatenation occurs here
    for (int k = 0; k < n; k++)
        str += "A";
    t = System.currentTimeMillis() - t;
    // Timed run ends
    System.out.printf("%d\t%d\n", n, t);
    return str;
}

虽然我可以得到程序的时间复杂度,但我想知道逐字符构建字符串的 space 复杂度 是多少?

首选解决内存管理问题的详细答案。 (我怀疑它也是二次的,因为字符串是不可变的,每次你都必须为不断增加的字符串分配新的内存)

注意: 这不是 String concatenation complexity in C++ and Java 的副本,因为它没有解决 space 复杂性 。我特别要求详细的 space 复杂度 分析。

它使用二次space。或者,更确切地说,分配了 space 的二次方数量,因为循环的每次迭代都会(至少在 JIT 没有做一些聪明的事情的代码中)分配一个新的 char 数组:

new char[1]
new char[2]
new char[3]
// Etc.

二次时间性能的原因是将字符串复制到这些越来越大的数组中。

您的代码效率很低,因为创建了一个隐式 StringBuilder 以在循环中添加单个字符。这个,

for (int k = 0; k < n; k++)
    str += "A";

相当于

for (int k = 0; k < n; k++)
    str = new StringBuilder(str).append("A").toString();

您可以通过使用单个 StringBuilder 来显着提高 space(和时间)性能(并且您 可以 显式调整它的大小)。喜欢,

StringBuilder sb = new StringBuilder(n);
for (int k = 0; k < n; k++)
    sb.append("A");
String str = sb.toString();

,在Java 8+中,您可以使用生成器并将其限制为n次并收集它。喜欢,

return Stream.generate(() -> "A").limit(n).collect(Collectors.joining());