迭代器的使用
当你第一次遇到某个迭代器时,总能得到几个引用着最有用的元素的迭代器:begin()
和 end()
是其中最好的例子。除此之外,许多算法也将返回迭代器。例如,标准算法 find
在一个序列里查找某个值,并返回引用着找到的那个元素的迭代器。利用 find
,我们可以统计出某一字符在一个 string
中出现的次数:
int count(const string& s, char c)
{
int n = 0;
string::const_iterator i = find(s.begin(), s.end(), c);
while(i!=s.end())
{
++n;
i = find(i+1, s.end(), c);
}
return n;
}
算法 find
返回一个引用着有关值在序列里的第一次出现的迭代器,或者是超过结束处一个位置的迭代器。现在考虑对 count
的简单调用中会出现什么情况:
void f()
{
string m = "Mary had a little lamb";
int a_count = count(m, 'a');
}
对 find()
的第一次调用将发现 Mary
里的 'a'
。这时返回的迭代器将指向这个字符,因而不是 s.end()
,所以我们就进入了循环。在循环中,我们又从 i+1
开始检索;也就是说,从所发现的 'a'
之后一个位置开始。随后的循环发现了另外三个 'a'
。完成了所有这些之后,find()
到达了结束处并返回 s.end()
,这使条件 i!=s.end()
为假,并使循环退出。
这里对 count()
的调用可以用图形方式表示如下
这里的箭头表示的是迭代器 i
的初始的、中间的和最后的位置。
很自然,算法 find
对于每个标准容器的工作都完全相同。根据这个情况,我们也可以按照同样的方式推广 count()
函数:
template<class C, class T> int count(const C& v, T val)
{
typename C::const_iterator i = find(v.begin(), v.end(), val); // "typename" 参见C.13.5节
int n = 0;
while(i!=v.end())
{
++n;
++i; // 跳过刚刚发现的元素
i = find(i, v.end(), val);
}
return n;
}
这样做能行,因此我们可以说
void f(list<complex>& lc, vector<string>& vs, string s)
{
int i1 = count(lc, complex(1, 3));
int i2 = count(vs, "Diogenes");
int i3 = count(s, 'x');
}
但是我们并不需要去定义 count
模板。由于统计出元素的出现次数是如此具有一般性的有用功能,标准库提供了这个算法。为了达到完全的通用性,标准库的 count
以一个序列作为参数,而不是以容器作为参数,因此我们应该采用如下的写法:
void f(list<complex>& lc, vector<string>& vs, string s)
{
int i1 = count(lc.begin(), lc.end(), complex(1, 3));
int i2 = count(vs.begin(), vs.end(), "Diogenes");
int i3 = count(s.begin(), s.end(), 'x');
}
采用序列的写法,将使我们也能把 count
用于内部数组,还可以对容器中的一部分做统计。例如,
void g(char cs[], int sz)
{
int i1 = count(&cs[0], &cs[sz], 'z'); // 数组中的'z'
int i2 = count(&cs[0], &cs[sz/2], 'z'); // 数组前一半中的'z'
}
🔚