我知道在循环中使用+ = on字符串需要O(n ^ 2)时间,其中n是循环数。但是如果循环最多运行20次。这会将时间复杂度改为O(1)吗?例如,
List<String> strList = new ArrayList<>();
//some operations to add string to strList
for(String str : strList) appendStr += str + ",";
我知道strList的大小永远不会超过20. strList中的每个字符串都少于20个字符。
如果在这种情况下字符串连接仍具有O(n ^ 2)时间复杂度,如果我希望我的算法具有更好的时间复杂度,最好是使用google.common.base.Joiner
吗?
答案 0 :(得分:2)
我实际上对此也非常感兴趣,主要是因为我们很快就会转到java-9
而我正在考虑将Joiner
替换为普通+
,因为它们现在是{{1}调用,似乎他们更快。这是我的测试(请注意,即使是普通的invokedynamic
方法也比StringBuilder
快7倍):
Joiner
结果如下:
@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.NANOSECONDS)
@Warmup(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 2, timeUnit = TimeUnit.SECONDS)
public class DifferentConcats {
public static void main(String[] args) throws RunnerException {
Options opt = new OptionsBuilder().include(DifferentConcats.class.getSimpleName()).verbosity(VerboseMode.EXTRA)
.build();
new Runner(opt).run();
}
@State(Scope.Thread)
public static class ThreadState {
public List<String> list;
@Setup(Level.Iteration)
public void setUp() {
int howMany = ThreadLocalRandom.current().nextInt(100, 10_000);
list = new ArrayList<>(howMany);
for (int i = 0; i < list.size(); ++i) {
list.add("" + i);
}
}
@TearDown(Level.Iteration)
public void tearDown() {
list = null;
}
}
@Benchmark
@Fork(1)
public String guavaJoiner(ThreadState state) {
return Joiner.on(',').join(state.list);
}
@Benchmark
@Fork(jvmArgsAppend = "-Djava.lang.invoke.stringConcat=BC_SB")
public String java9StringBuilder(ThreadState state) {
String s = "";
List<String> list = state.list;
int size = list.size();
for (int i = 0; i < size; ++i) {
s += list.get(i) + ",";
}
return s;
}
@Benchmark
@Fork(1)
public String java9Default(ThreadState state) {
String s = "";
List<String> list = state.list;
int size = list.size();
for (int i = 0; i < size; ++i) {
s += list.get(i) + ",";
}
return s;
}
答案 1 :(得分:0)
由于JVM运行时优化,不可能声明Guava的Joiner
能够100%保证更有效,在某些情况下,简单连接可以更快地工作。
这就是说,更喜欢Joiner
(或类似于利用StringBuilder
的结构)来连接集合,因为它的可读性和性能通常更好。
答案 2 :(得分:0)
在一种非常迂腐的意义上,如果您的输入上限是固定大小,那么对该输入执行的任何操作都是有效的恒定时间,但这会错过这种分析的目的。如果您对时间复杂度感兴趣,请检查代码在asymptotic情况下的行为,而不是单个特定输入的行为。
即使你将列表的大小限制为20个元素,你仍然在做O(n ^ 2)“工作”以连接元素。与使用StringBuilder
或更高级别工具(例如设计)的Joiner
或更高级别工具相比,使其比重复连接更有效。 Joiner
只需做O(n)“工作”就可以构造你需要的字符串。
简单地说,永远不会做出理由:
for(String str : strList) appendStr += str + ",";
而不是:
Joiner.on(',').join(strList);
答案 3 :(得分:0)
我找到了一篇很棒的博客文章,详细介绍了每种串联技术的性能java-string-concatenation-which-way-is-best
注:串联性能随否而变化。要连接的字符串。例如,要连接1-10个字符串,这些技术最有效-StringBuilder,StringBuffer和Plus运算符。为了连接100多个字符串-Guava Joiner,apache的stringsUtils库也很好用。
请浏览上述博客。它确实很好地解释了各种串联技术的性能。
谢谢。