Java StringBuilder.setLength()-时间复杂度是否为O(1)?
我计划对StringBuilder中的最后一个字符执行大量删除操作。使用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为例,
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: }