java:使用StringBuilder插入开头


94

我只能用String来做到这一点,例如:

String str="";
for(int i=0;i<100;i++){
    str=i+str;
}

有没有办法用StringBuilder做到这一点?谢谢。

Answers:


187
StringBuilder sb = new StringBuilder();
for(int i=0;i<100;i++){
    sb.insert(0, Integer.toString(i));
}

警告: 它违背了的目的StringBuilder,但确实满足您的要求。


更好的技术(尽管仍然不理想):

  1. 反转要插入的每个字符串。
  2. 每个字符串附加StringBuilder
  3. 完成后反转整个 StringBuilder过程。

这将打开一个O(ñ ²)溶液到O(Ñ)。


2
...因为它使AbstractStringBuilder所有内容都移到插入索引之外,以便为插入的内容找到空间。但是,这只是实现细节,而不是原理之一。
entonio

1
@entonio:确实,但这是一个非常关键的细节。:)
user541686

1
我看到,看来我不应该再使用StringBuilder,非常感谢
user685275 2011年

@ user685275:是的,如果您需要向后插入,那么您确实需要可以在字符串开头插入的内容。我认为最简单的解决方案是上述技术(两次反转),尽管您可以使用char数组创建更好的类(可能希望研究“双端队列”)。
user541686 2011年

1
@rogerdpack:我要说的是机制,而不是目的。目的是要比字符串操作渐近地更快,如果使用不正确,它将不会如此。
user541686 '19

31

您可以使用 strbuilder.insert(0,i);


2
为什么这会引起如此多的赞!该类定义不正确-仅是方法调用的签名!
JGFMK

13

也许我缺少了一些东西,但是您想用一个看起来像这样的String结束,对"999897969594...543210"吗?

StringBuilder sb = new StringBuilder();
for(int i=99;i>=0;i--){
    sb.append(String.valueOf(i));
}

奇怪的这个帖子并没有得到太多的投票,同时提供环路的巧妙操纵的解决方案,
NOM-MON-IR

1
@ nom-mon-ir他只是反转字符串。它没有回答如何在左侧追加。
雷蒙德·谢农

达到理想的效果。
斯帕克

我认为在某些情况下,您可以使用此方法,而不是尝试破解一种使用StringBuilder真正潜力的在开始处进行插入的方法。无论如何,在某些情况下您无法反转循环,因此您还需要其他答案。
PhoneixS

7

作为一种替代解决方案,您可以使用LIFO结构(如堆栈)来存储所有字符串,完成后只需将它们全部取出并放入StringBuilder中即可。它自然会颠倒放置在其中的项目(字符串)的顺序。

Stack<String> textStack = new Stack<String>();
// push the strings to the stack
while(!isReadingTextDone()) {
    String text = readText();
    textStack.push(text);
}
// pop the strings and add to the text builder
String builder = new StringBuilder(); 
while (!textStack.empty()) {
      builder.append(textStack.pop());
}
// get the final string
String finalText =  builder.toString();

4
ArrayDeque应该代替Stack。“ {@link Deque}接口及其实现提供了一套更完整和一致的LIFO堆栈操作,应优先使用此类。”
Luna 2016年

5

该线程已经很老了,但是您也可以考虑将StringBuilder填充的递归解决方案。这样可以防止任何反向处理等。只需要使用递归设计迭代并仔细确定退出条件即可。

public class Test {

    public static void main(String[] args) {
        StringBuilder sb = new StringBuilder();
        doRecursive(sb, 100, 0);
        System.out.println(sb.toString());
    }

    public static void doRecursive(StringBuilder sb, int limit, int index) {
        if (index < limit) {
            doRecursive(sb, limit, index + 1);
            sb.append(Integer.toString(index));
        }
    }
}

3

当我偶然发现这篇文章时,我有一个类似的要求。我想要一种快速的方法来构建一个可以从两端都扩展的字符串。在前面和后面任意添加新字母。我知道这是一篇过时的文章,但是它启发了我尝试一些创建字符串的方法,并且我认为我会分享自己的发现。我还在其中使用了一些Java 8构造,这些构造在情况4和5中可以优化速度。

https://gist.github.com/SidWagz/e41e836dec65ff24f78afdf8669e6420

上面的要点包含任何人都可以运行的详细代码。在这种情况下,我采取了几种方法来增加字符串;1)附加到StringBuilder,2)如@Mehrdad所示,插入到StringBuilder的前面,3)从StringBuilder的前面和结尾部分插入,4)使用列表从结尾追加,5)使用双端队列从前面追加。

// Case 2    
StringBuilder build3 = new StringBuilder();
IntStream.range(0, MAX_STR)
                    .sequential()
                    .forEach(i -> {
                        if (i%2 == 0) build3.append(Integer.toString(i)); else build3.insert(0, Integer.toString(i));
                    });
String build3Out = build3.toString();


//Case 5
Deque<String> deque = new ArrayDeque<>();
IntStream.range(0, MAX_STR)
                .sequential()
                .forEach(i -> {
                    if (i%2 == 0) deque.addLast(Integer.toString(i)); else deque.addFirst(Integer.toString(i));
                });

String dequeOut = deque.stream().collect(Collectors.joining(""));

我将只关注前面的附加案例。情况2和情况5。StringBuilder的实现在内部决定内部缓冲区的增长方式,除了在前置附加的情况下将所有缓冲区从左移到右之外,这还限制了速度。虽然直接插入到StringBuilder的前面所花费的时间增长到了很高的值(如@Mehrdad所示),但是如果只需要长度少于90k个字符的字符串(仍然很多),则前面的插入将通过在末尾追加来构建具有相同长度的String的同时构建一个String。我的意思是,时间惩罚的确确实存在并且是巨大的,但是只有当您必须构建非常大的字符串时。如我的示例所示,可以使用双端队列并在最后连接字符串。

实际上,情况2的性能比情况1快得多,我似乎并不了解。我假设StringBuilder中内部缓冲区的增长在前附加和后附加的情况下是相同的。我什至将最小堆设置为非常大的数量,以避免延迟堆增长(如果这样做会起作用)。也许有更好理解的人可以在下面发表评论。


1
Difference Between String, StringBuilder And StringBuffer Classes
String
String is immutable ( once created can not be changed )object. The object created as a
String is stored in the Constant String Pool.
Every immutable object in Java is thread-safe, which implies String is also thread-safe. String
can not be used by two threads simultaneously.
String once assigned can not be changed.
StringBuffer
StringBuffer is mutable means one can change the value of the object. The object created
through StringBuffer is stored in the heap. StringBuffer has the same methods as the
StringBuilder , but each method in StringBuffer is synchronized that is StringBuffer is thread
safe .
Due to this, it does not allow two threads to simultaneously access the same method. Each
method can be accessed by one thread at a time.
But being thread-safe has disadvantages too as the performance of the StringBuffer hits due
to thread-safe property. Thus StringBuilder is faster than the StringBuffer when calling the
same methods of each class.
String Buffer can be converted to the string by using
toString() method.

    StringBuffer demo1 = new StringBuffer("Hello") ;

// The above object stored in heap and its value can be changed.
/
// Above statement is right as it modifies the value which is allowed in the StringBuffer
StringBuilder
StringBuilder is the same as the StringBuffer, that is it stores the object in heap and it can also
be modified. The main difference between the StringBuffer and StringBuilder is
that StringBuilder is also not thread-safe.
StringBuilder is fast as it is not thread-safe.
/
// The above object is stored in the heap and its value can be modified
/
// Above statement is right as it modifies the value which is allowed in the StringBuilder

1
欢迎使用stackoverflow。请说明代码的作用以及如何解决问题。
bad_coder

1

您可以使用带有偏移量的insert方法。因为将offset设置为'0'意味着您将追加到StringBuilder的前面。

StringBuilder sb = new StringBuilder();
for(int i=0;i<100;i++){
    sb.insert(0,i);
}

注意:由于insert方法接受所有类型的基元,因此可以用于int,long,char []等。


0

怎么样:

StringBuilder builder = new StringBuilder();
for(int i=99;i>=0;i--){
    builder.append(Integer.toString(i));
}
builder.toString();

要么

StringBuilder builder = new StringBuilder();
for(int i=0;i<100;i++){
  builder.insert(0, Integer.toString(i));
}
builder.toString();

但是,与此同时,您正在执行操作O(N ^ 2)而不是O(N)。

来自Java文档的代码段:

将Object参数的字符串表示形式插入此字符序列。总体效果与方法将第二个参数转换为 String.valueOf(Object)字符串一样,然后将该字符串的字符以指定的偏移量插入到此字符序列中。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.