Consider this piece of code:
public String joinWords(String[] words) { String sentence = ""; for(String w : words) { sentence = sentence + w; } return sentence; }
On each concatenation a new copy of the string is created, so that the overall complexity is O(n^2)
. Fortunately in Java we could solve this with a StringBuffer
, which has O(1)
complexity for each append, then the overall complexity would be O(n)
.
While in C++, std::string::append()
has complexity of O(n)
, and I'm not clear about the complexity of stringstream
.
In C++, are there methods like those in StringBuffer
with the same complexity?
On each concatenation a new copy of the string is created, so that the overall complexity is O(n^2). In Java, the complexity of s1. concat(s2) or s1 + s2 is O(M1 + M2) where M1 and M2 are the respective String lengths.
Let me say the reason that string concatenation is slow is because strings are immutable. This means every time you write "+=", a new String is created. This means the way you build up your string is in the worst case, O(n2).
Therefore, concatenation is much faster than String.
String concatenation It can be a bit surprising, but this code actually runs in O(N2) time. The reason is that in Java strings are immutable, and as a result, each time you append to the string new string object is created. The loop in the code does 1 + 2 + 3 + ... + N = N * (N + 1) / 2 = O(N2) operations.
C++ strings are mutable, and pretty much as dynamically sizable as a StringBuffer. Unlike its equivalent in Java, this code wouldn't create a new string each time; it just appends to the current one.
std::string joinWords(std::vector<std::string> const &words) { std::string result; for (auto &word : words) { result += word; } return result; }
This runs in linear time if you reserve
the size you'll need beforehand. The question is whether looping over the vector to get sizes would be slower than letting the string auto-resize. That, i couldn't tell you. Time it. :)
If you don't want to use std::string
itself for some reason (and you should consider it; it's a perfectly respectable class), C++ also has string streams.
#include <sstream> ... std::string joinWords(std::vector<std::string> const &words) { std::ostringstream oss; for (auto &word : words) { oss << word; } return oss.str(); }
It's probably not any more efficient than using std::string
, but it's a bit more flexible in other cases -- you can stringify just about any primitive type with it, as well as any type that has specified an operator <<(ostream&, its_type&)
override.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With