Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/384.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 StringBuilder.setLength()-时间复杂度是否为O(1)?_Java_Big O_Time Complexity - Fatal编程技术网

Java StringBuilder.setLength()-时间复杂度是否为O(1)?

Java StringBuilder.setLength()-时间复杂度是否为O(1)?,java,big-o,time-complexity,Java,Big O,Time Complexity,我计划对StringBuilder中的最后一个字符执行大量删除操作。使用sb.setLength(sb.length()-1)的解决方案在我看来不错。然而,由于这些删除将是一个循环,我需要知道它的复杂性 我的理解是,此操作只是减少StringBuilder对象的某些私有属性,并且不执行字符本身的任何复制/克隆/复制,因此它在时间上是O(1),应该工作得很快 我说得对吗?如果新的长度小于旧的长度,则为O(1),在您的情况下就是这样 JDK的源代码可以在线获得,因此您可以自己检查。以Java8为例,

我计划对StringBuilder中的最后一个字符执行大量删除操作。使用
sb.setLength(sb.length()-1)的解决方案在我看来不错。然而,由于这些删除将是一个循环,我需要知道它的复杂性

我的理解是,此操作只是减少StringBuilder对象的某些私有属性,并且不执行字符本身的任何复制/克隆/复制,因此它在时间上是O(1),应该工作得很快

我说得对吗?

如果新的长度小于旧的长度,则为O(1),在您的情况下就是这样

JDK的源代码可以在线获得,因此您可以自己检查。以Java8为例,
setLength
在中实现。它做了几件事:

  • 如果新长度小于0,则会出现错误
  • 确保StringBuilder具有足够的容量以适应新的长度(如果要缩短长度,它会这样做)
  • 如果要延长长度(不是),则为额外长度填充0
  • this.count
    字段设置为指定的长度
总而言之:

  • 如果你要缩短长度,这是O(1)-一些快速检查,然后一个字段分配
  • 如果增加长度,但旧容量仍然足够,则为O(N),其中N是附加长度(例如,如果有一个100长度生成器,则将其缩短为10,现在将其增加为90,则N将为90-10=80)
  • 如果你增加长度,这样容量就需要增加,它是O(N),其中N是新的容量

来自文档:

设置字符序列的长度。序列将更改为新的字符序列,其长度由参数指定。对于每个小于newLength的非负索引k,如果k小于旧字符序列的长度,则新字符序列中索引k处的字符与旧序列中索引k处的字符相同;否则,它是空字符“\u0000”。换句话说,如果newLength参数小于当前长度,则该长度将更改为指定的长度。 如果newLength参数大于或等于当前长度,则会附加足够的空字符('\u0000'),以便length成为newLength参数

newLength参数必须大于或等于0


我会说是的。但我不会从时间复杂性的角度来看它。我们在循环中使用StringBuilder而不是String的原因是字符串是不可变的。因此,当我们试图更改字符串对象时,总是会创建一个新的字符串对象。更改StringBuilder对象的长度时,不会创建新对象。

setLength的复杂性因操作而异(增加或减少) 递增操作的复杂性不是O(1),我认为它是O(n),因为在这个操作中将生成新的数组,并且stringbuilder的每个未使用的字节都将替换为“\0”字节

但reduce操作的复杂度是O(1),因为在这个操作中,只会更改字符数

StringBuilder类源文件中有setLength方法的源

225:public void setLength(int newLength)
226:   {
227:if(新长度<0)
228:抛出新StringIndexOutOfBoundsException(newLength);
229: 
230:int-valueLength=value.length;
231: 
232:/*始终调用ensureCapacity以保留写入时的拷贝
233:语义学*/
234:保证能力(新长度);
235: 
236:if(新长度<值长度)
237:       {
238://*如果StringBuilder的价值刚刚增长,那么我们知道
239:值是新分配的,并且计数和
240:newLength用“\0”填充*/
241:计数=新长度;
242:       }
243:还有吗
244:       {
245:/*StringBuilder的值不需要增长。但是,
246:我们应该清除可能存在的任何积垢*/
247:while(计数<新长度)
248:值[count++]='\0';
249:       }
250:   }

除了在线提供源代码外,您在安装JDK时还可以获得一份副本,一个好的IDE将自动使用它,因此您可以看到大多数运行时库类的源代码(例如,如果使用Eclipse,在类或方法上按F3)。如果您编程Java,您应该使用IDE,而且它应该允许您查看大多数运行时库类的源代码,因此只要花1分钟的研究时间,您就应该能够自己回答这个问题。这个答案是误导性的,因为如果新长度大于基础数组的当前长度,则需要上一个数组的完整副本。我发现@yshavit的答案更准确
 225:   public void setLength(int newLength)
 226:   {
 227:     if (newLength < 0)
 228:       throw new StringIndexOutOfBoundsException(newLength);
 229: 
 230:     int valueLength = value.length;
 231: 
 232:     /* Always call ensureCapacity in order to preserve copy-on-write
 233:        semantics.  */
 234:     ensureCapacity(newLength);
 235: 
 236:     if (newLength < valueLength)
 237:       {
 238:         /* If the StringBuilder's value just grew, then we know that
 239:            value is newly allocated and the region between count and
 240:            newLength is filled with '\0'.  */
 241:     count = newLength;
 242:       }
 243:     else
 244:       {
 245:     /* The StringBuilder's value doesn't need to grow.  However,
 246:        we should clear out any cruft that may exist.  */
 247:     while (count < newLength)
 248:           value[count++] = '\0';
 249:       }
 250:   }