重复调用vector::size()
会重新计算元素数量(O(n)
计算),还是将此值存储在某处(O(1)
查找)。例如,在下面的代码中
// Split given string on whitespace
vector<string> split( const string& s )
{
vector<string> tokens;
string::size_type i, j;
i = 0;
while ( i != s.size() ) {
// ignore leading blanks
while ( isspace(s[i]) && i != s.size() ) {
i++;
}
// found a word, now find its end
j = i;
while ( !isspace(s[j]) && j != s.size() ) {
j++;
}
// if we found a word, add it to the vector
if ( i != j ) {
tokens.push_back( s.substr(i, j-i) );
i = j;
}
}
return tokens;
}
假设s
可能非常大,我应该只调用s.size()
一次并存储结果吗?
谢谢!
答案 0 :(得分:5)
在大多数情况下,您应该单独保留分配,除非您提前知道项目数,因此您可以保留正确的空间量。
至少在我知道的每种情况下,std::vector::size()
只返回一个存储值,因此它具有恒定的复杂性。从理论上讲,C ++标准允许它做其他事情。有理由允许其他容器,主要是std::list
,而不是为那些容器做特殊情况,他们只是建议所有容器的恒定时间,而不是任何容器。我无法想象一个vector::size
计算了元素 - 我真的没有这样的事情存在过。
P.S。,更简单的方法来执行上面的代码所做的事情,就像这样:
std::vector<string> split(std::string const &input) {
vector<string> ret;
istringstream buffer(input);
copy(istream_iterator<string>(input),
istream_iterator<string>(),
back_inserter(ret));
return ret;
}
编辑:IMO, C ++标准库,由Nicolai Josuttis撰写,是关于此类事情的绝佳参考。
答案 1 :(得分:4)
容量增量的实际大小取决于实现,但必须(大致)指数以支持容器的复杂性要求。例如,Visual C ++标准库将精确分配前几个元素所需的空间(五个,如果我没记错的话),然后在那之后以指数方式增加大小。
大小必须以某种方式存储在向量中,否则它不知道序列的结尾在哪里!但是,它可能不一定存储为整数。 Visual C ++实现(再次作为示例)存储三个指针:
大小可以从(1)和(2)计算出来;容量可以从(1)和(3)计算出来。
其他实现可能会以不同方式存储信息。
答案 2 :(得分:1)
这是特定于图书馆的。您可以控制增量分配,但可能不会。
存储大小,因此检索速度非常快(恒定时间)。它还有什么用呢? C无法一般地知道内存位置是否是“真实数据”。
答案 3 :(得分:1)
调整大小机制通常是固定的。 (大多数编译器在达到限制时将向量的大小加倍。)C ++标准指定无法控制此行为。
每当您插入/删除元素时,内部都会更新大小,当您调用size()
时,会立即返回。所以,是的,它是 O(1)。
答案 4 :(得分:1)
当元素数量达到此大小时,将调整矢量大小。这个尺寸编译器是否具体?我可以控制它吗?这是个好主意吗?
通常,这是特定于库的行为,但是可能可以通过指定自定义分配器来影响此行为,这是非常重要的工作。
重复调用vector :: size()会重新计算元素数量(O(n)计算),或者将此值存储在某处(O(1)lookup)。
大多数实现将大小存储为成员。这是一个单一的内存读取。
答案 5 :(得分:1)
与您的实际问题无关,但这是一种更“STL”的方式来做您正在做的事情:
vector<string> split(const string& s)
{
istringstream stream(s);
istream_iterator<string> iter(stream), eos;
vector<string> tokens;
copy(iter, eos, back_inserter(tokens));
return tokens;
}