Java 从字符堆栈构造字符串的有效且简洁的方法是什么

Java 从字符堆栈构造字符串的有效且简洁的方法是什么,java,java-8,stack,Java,Java 8,Stack,假设我有一堆- O (stack top) L L E H (stack bottom) 将其转换为“HELLO”的简明方式是什么 现在我这样做了- private static String getString(Stack<Character> charStack) { StringBuilder output = new StringBuilder(); while (!charStack.isEmpty()) { output.append(charSt

假设我有一堆-

O (stack top)
L
L
E
H (stack bottom)
将其转换为“HELLO”的简明方式是什么

现在我这样做了-

private static String getString(Stack<Character> charStack) {
  StringBuilder output = new StringBuilder();

  while (!charStack.isEmpty()) {
      output.append(charStack.pop());    
  }

  return output.reverse().toString();
}
私有静态字符串getString(Stack charStack){
StringBuilder输出=新的StringBuilder();
而(!charStack.isEmpty()){
append(charStack.pop());
}
返回output.reverse().toString();
}

请注意,
charStack.pop()
实际上从堆栈中删除了元素-您确定这是有意的吗

您可以这样做,而无需删除元素:

private static String getString(Stack<Character> charStack) {
    StringBuilder output = new StringBuilder();

    for (Character c : charStack) {
        output.append(c);    
    }

    return output.reverse().toString();
}
私有静态字符串getString(Stack charStack){
StringBuilder输出=新的StringBuilder();
for(字符c:字符堆栈){
输出。追加(c);
}
返回output.reverse().toString();
}

使用
映射
收集器
,实现相关代码意图的一种方法是:

return charStack.stream().map(Object::toString).collect(Collectors.joining());
编辑:从注释中可以看到,如果清空堆栈是有意操作,则可以更新代码以包含以下行为:

String output = charStack.stream().map(Object::toString).collect(Collectors.joining());
charStack.clear();
return output;
注 我无意中以为您正在搜索更快的版本。然而,我决定把讨论留在这里,因为它可能对未来的读者有用


分析 对于给定的输入,您不可能获得更好的版本,至少在讨论复杂度类时是这样。您的
堆栈
只能从最后一项遍历到第一项,而不是按照
字符串
的正确顺序

您不能直接使用最后的
字符串需要先反转的知识

让我们看看您的代码,让我们用
n
表示堆栈的大小:

private static String getString(Stack<Character> charStack) {
    StringBuilder output = new StringBuilder();

    // Yields n iterations
    while (!charStack.isEmpty()) {
        output.append(charStack.pop());    
    }

    // reverse creates n iterations
    // toString creates n iterations
    return output.reverse().toString();
}
我们总共有
2*n
次迭代,也产生
O(n)

因此,如果您知道大小,它可能确实会稍微快一点。然而,差别不会那么大,它的
O(n)
也是如此


大小不详 如果您不知道可以使用
ArrayList
交换
char[]
LinkedList
也可以,但速度可能较慢):

ArrayList textChars=new ArrayList();
//产生n次迭代
for(char c:charStack){
//设置ArrayList
//设置是在固定时间内完成的
textChars.add(charStack.pop());
}
//不幸的是,没有好的方法
//将ArrayList直接转换为字符串
StringBuilder sb=新的StringBuilder();
//反向迭代ArrayList,反之亦然
//方向是免费的
//产生n次迭代
对于(int i=textChars.size()-1;i>=0;i--){
某人追加(textChars.get(i));
}
//产生n次迭代
字符串text=sb.toString();

现在我们有大约
3*n次
迭代,但由于
ArrayList
Character
的缘故,开销更大。在没有做过实验的情况下,如果大小未知,我会说你的方法比任何方法都好。

定义“最佳”,你尝试了什么?你说的堆栈是指java.util.stack吗?嗯,定义好了,编辑好了。是的,java.util.Stack请注意,
Stack
是一个非常古老的类,不应该再使用它了。它甚至在自己的文档中说,使用流切换到
Deque
的实现,比如
ArrayDeque
LinkedList
。还有一点值得注意,堆栈的顺序应该与被推的顺序相反。是的,绝对要知道这一点。@shakhawat在这种情况下,你的方法是正确的。我只是不希望从函数名中看到这一点,而你没有解释这是一个想要的副作用。@TobiasWeimer这似乎是一个澄清,可能是对问题的评论,而不是答案。因为循环的条件是
!charStack.isEmpty()
,这似乎是已经知道的。虽然这个答案本身很有用,但它并没有回答OP的问题,它只是一个大注释。我不是一个java爱好者,但没有reduce方法/函数吗?例如,将其写成,
collection.reduce(初始值,lambda)
?ruby:
collection.reverse.injection(“”{e,i | i+=e}
js:
collection.reduce((i,e)=>i+e)
根据OP自己的代码示例,
reverse
不是必需的。@Holger请参见答案中的注释。@marmeladze:,优化为使用可变的
StringBuilder
,而不是创建中间字符串对象。如果再进一步,
charStack.stream().collect(StringBuilder::new,StringBuilder::append,StringBuilder::append).toString()使用更少的中间对象。当然,
charStack.stream()(如果原始代码的属性很重要)…关于“大小未知”,该代码段中的
size
是什么?在该上下文中,这似乎是不可能的,但最后一个解决方案是“如果不知道大小,可以与ArrayList交换char[]但是仍然在第一个
语句中使用
size
变量…@AxelH确实,这里太晚了,对不起。
int size = ...
char[] textChars = new char[size];

// Yields n iterations
for (int i = 0; i < size; i++) {
    // Reversely set the array
    // Setting is done in constant time
    textChars[size - i - 1] = charStack.pop();
}

// Convert the textChars to String
// without using reverse methods
// Yields n iterations
String text = String.valueOf(textChars);
ArrayList<Character> textChars = new ArrayList<>();

// Yields n iterations
for (char c : charStack) {
    // Set the ArrayList
    // Setting is done in constant time
    textChars.add(charStack.pop());
}

// Unfortunately there is no nice method
// to directly convert ArrayList to String
StringBuilder sb = new StringBuilder();

// Reversely iterate the ArrayList, the reverse
// direction comes at no additional cost
// Yields n iterations
for (int i = textChars.size() - 1; i >= 0; i--) {
    sb.append(textChars.get(i));
}

// Yields n iterations
String text = sb.toString();