如果一个类中实现了重载括号()运算符,即operator(),那么这个类的对象就是一个函数对象。因为函数对象实现了operator(),所以它就有了类似函数的行为,可以像函数一样来调用它,所以函数对象又称为仿函数:
class CSquare
{
public:
void operator()(int& x)
{
x = x * x;
}
};
int main()
{
int i = 10;
CSquare sq;
sq(i);
cout << i << endl; //输出为100
int n = 5;
CSquare()(n); //CSquare()会生成一个CSquare对象,CSquare()(n)相当于是调用该对象的operator方法
cout << n << endl; //输出为25
return 0;
}
谓词就是函数或函数对象,并且它的调用返回值是一个能用作条件的值,比如bool。一元谓词就是带一个参数的函数,二元谓词就是带两个参数的函数。
1、sort()、stable_sort()、unique()
如sort算法默认使用元素类型的<运算符来进行排序,得到的排序结果是升序的。如果容器元素的类型是自定义类型或者我们希望排序结果与<所定义的顺序不同的话,那么我们需要将元素类重载operator<,或者我们提供一个可调用对象来传给sort的第三个参数。可调用对象有三种:函数指针、函数对象、lambda表达式。
因为list 容器不提供随机访问迭代器,所以应该使用其成员方法list::sort()来进行排序,sort() 有两个版本:无参 sort() 函数将所有元素升序排列,第二个版本的 sort() 接受一个函数对象或 lambda 表达式作为参数。
比如我们想要sort实现降序排序的话可以使用函数指针、函数对象、lambda三种来传入():
bool myFunction(int i, int j) { return (i > j); }
class myClass
{
public:
bool operator() (int i, int j) { return (i > j); }
};
int main()
{
vector<int> v = { 5, 2, 4, 3, 5 };
sort(v.begin(), v.end(), myClass());
//sort(v.begin(), v.end(), myFunction);
/*sort(v.begin(), v.end(), [](int i, int j) {
return (i > j);
});*/
for (auto iter = v.begin(); iter != v.end(); iter++)
cout << *iter << endl;
return 0;
}
对于下面的容器,要求以字符串"oo"出现的位置排序:
vector<string> v;
v.push_back("aooc");
v.push_back("ooa");
v.push_back("oo");
v.push_back("aboo");
v.push_back("oo");
string strSearch = "oo";
sort(v.begin(), v.end(), [strSearch](string s1, string s2) {
return s1.find(strSearch) < s2.find(strSearch);
});
for (auto item : v)
{
cout << item << endl;
}
上面代码输出为:
如果字符串中"oo"出现的位置相同,那么我们就按照整个字符串的长度来排序, 这样对于整个元素就是"oo"的元素就会排在最前面:
sort(v.begin(), v.end(), [strSearch](string s1, string s2) {
if (s1.find(strSearch) == s2.find(strSearch))
return s1.length() < s2.length();
return s1.find(strSearch) < s2.find(strSearch);
});
输出为:
有一点需要注意的是,对于元素“相等”的情况也应该返回false而不是返回true,否则会出现排序异常。
STL有一组预定义的函数对象模板,如equal<T>、less<T>、less_equal<T>、greater<T>等。如果容器元素是int、float、string等标准类型,就可以直接使用它们来创建一个二元谓词,从而不必自己再定义,eg:
int main()
{
vector<int> v = list_of(5) (2) (4) (3) (5);
sort(v.begin(), v.end(), greater<int>());
for (auto iter = v.begin(); iter != v.end(); iter++)
cout << *iter << endl;
return 0;
}
还有一个稳定排序算法stable_sort(),它是将符合相等条件的元素按照原来的顺序存放,比对对于一个vector<string>,我们想按照每个元素的长度来升序排序,那么
传入的函数对象应该是这样:
class CCompare
{
public:
bool operator()(const string& str1, const string& str2)
{
return str1.length() < str2.length();
}
};
int main()
{
vector<string> vc;
vc.push_back("abc");
vc.push_back("ab");
vc.push_back("ac");
vc.push_back("a");
sort(vc.begin(), vc.end(), CCompare());
for (auto iter = vc.begin(); iter != vc.end(); iter++)
cout << *iter << endl;
return 0;
}
可以看到,元素"ab"和"ac"的长度是相等的,如果使用sort()排序的话二者的排序顺序不定,如果使用stable_sort的话会使用二者原来的位置来对二者进行存放。
unique()算法可以“去除”容器中相邻元素的重复元素,所以我们一般先将容器排好序再使用unique()。因为STL算法不能直接添加或删除元素,所以unique()“去除”重复元素后容器大小不变,并返回不重复元素中最后一个元素之后的迭代器,这个迭代器到end()之间的元素的值是不确定的,所以一般再使用容器的成员函数erase()来删除这些无用的元素:
std::vector<int> vc{ 5, 1, 2, 1, 3, 3 };
std::sort(vc.begin(), vc.end());
//auto iter = std::unique(vc.begin(), vc.end());
auto iter = std::unique(vc.begin(), vc.end(), [](const int& n1, const int& n2) {
return (n1 == n2);
});
vc.erase(iter, vc.end()); //result:1, 2, 3, 5
map中的元素是有序存放的,比如对于key为int类型的话默认是按照key由小到大存放的,如果我们想要由大到小存放的话可以指定map的第三个泛型的类型,这个类型必须是一个实现了operator()的类:
struct classcomp {
bool operator() (const char& lhs, const char& rhs) const
{
return lhs > rhs;
}
};
int main()
{
std::map<char, int, classcomp> m;
m.insert({ 'a', 10 });
m.insert({ 'b', 10 });
m.insert({ 'c', 10 });
m.insert({ 'd', 10 });
//输出为'd'、'c'、'b'、'a'
for (auto& item : m) {
std::cout << item.first << std::endl;
}
}
需要注意,上面使用的并不是函数对象,而是指定泛型类型为classcomp类型,像std::sort()的第三个参数这种传入的参数是函数对象,所以可以使用lambda表达式。map也可以通过std::function来使用lambda:
std::map<char, int, std::function<bool(const char& lhs, const char& rhs)>> m([](const char& lhs, const char& rhs) {
return lhs > rhs;
});
m.insert({ 'a', 10 });
m.insert({ 'b', 10 });
m.insert({ 'c', 10 });
m.insert({ 'd', 10 });
//输出为'd'、'c'、'b'、'a'
for (auto& item : m) {
std::cout << item.first << std::endl;
}
如果map的key元素类型是自定义类型的话,必须像上面那样来指定map元素的比较方法,也可以直接在自定义的类中实现operator<来指定元素的比较方法,如下所示:
class CItem
{
public:
CItem(int n) : m_num(n){}
bool operator<(const CItem& item)const
{
return m_num < item.m_num;
}
int getNum(){ return m_num; }
private:
int m_num;
};
int main()
{
std::map<CItem, char> m;
m.insert({ {2}, 'a' });
m.insert({ {1}, 'b' });
m.insert({ {4}, 'c' });
m.insert({ {3}, 'd' });
//输出为1、2、3、4
for (std::pair<CItem, char> item : m) { //item是m中元素的一个副本
std::cout << item.first.getNum() << std::endl;
}
auto item = m.begin()->first; //item是m中第一个元素的一个副本
int n = item.getNum();
for (auto item : m) { //这里的item实际上为std::pair<const CItem, char>类型
std::cout << item.first.getNum() << std::endl; //编译出错,除非将getNum()声明为const
}
auto iter = m.begin(); //map的迭代器类型实际上是std::map<const CItem, char>::iterator类型
iter->first.getNum(); //编译出错,除非将getNum()声明为const
}
从上面的代码可以看出,为了防止我们改变map的key,map的迭代器或for循环中的auto类型中的key都自动称为了const类型,这一点需要注意,防止编译出错。
map、set默认是按照key大小进行排序的,使用insert插入key相同的元素的话不会进行替换([]或者insert_or_assign()则会进行替换),也就是说按照哪个排序的话哪个数据就不会有重复的。比如下面的set,按照的是CItem的m_n进行的排序,所以不会存在m_n相等的元素,因为如果插入的CItem元素的m_n已经存在的话,不会进行替换:
class CItem {
public:
CItem(int n, int m) {
m_n = n;
m_m = m;
}
bool operator<(const CItem& item)const {
return this->m_n < item.m_n;
}
private:
int m_n = 0;
int m_m = 0;
};
int main()
{
std::set<CItem> s;
//执行下面四条语句后,s 中的值顺序为:CItem(1, 100)、CItem(2, 200)、CItem(3, 100)
s.insert(CItem(3, 100));
s.insert(CItem(1, 100));
s.insert(CItem(2, 200));
s.insert(CItem(2, 2000));
}
如果将上面代码修改为按照m_m排序的话,则set中不会存在m_m相等的元素:
class CItem {
public:
CItem(int n, int m) {
m_n = n;
m_m = m;
}
bool operator<(const CItem& item)const {
return this->m_m < item.m_m;
}
private:
int m_n = 0;
int m_m = 0;
};
int main()
{
std::set<CItem> s;
//执行下面四条语句后,s 中的值顺序为:CItem(3, 100)、CItem(2, 200)、CItem(2, 2000)
s.insert(CItem(3, 100));
s.insert(CItem(1, 100));
s.insert(CItem(2, 2000));
s.insert(CItem(2, 200));
}
如果我们想要set按照m_n进行排序,如果m_n相等的话按照m_m排序(即m_n可以相同,m_n相同的时候m_m不能相同),可以如下修改代码:
class CItem {
public:
CItem(int n, int m) {
m_n = n;
m_m = m;
}
bool operator<(const CItem& item)const {
if (this->m_n == item.m_n)
return this->m_m < item.m_m;
return this->m_n < item.m_n;
}
private:
int m_n = 0;
int m_m = 0;
};
int main()
{
std::set<CItem> s;
//执行完以下语句后,s 中的值顺序为:CItem(1, 100)、CItem(2, 200)、CItem(2, 2000)、CItem(3, 100)
s.insert(CItem(3, 100));
s.insert(CItem(1, 100));
s.insert(CItem(2, 200));
s.insert(CItem(2, 2000));
}
再比如下面的map,最后一条插入的数据不会执行,因为map的比较方法比较的是SFoo的number成员,最后一条插入数据的number与第一条数据的number相等。那么我们并没有提供判断相等的方法,map是怎么判断元素相等的呢,答案就是可以通过传入的比较方法来判断是否相等:if(!fun(s1, s2) && !fun(s2, s1))。
struct SFoo
{
std::string name;
int number;
};
int main(int argc, char** argv)
{
std::map<SFoo, std::string, std::function<bool(const SFoo&, const SFoo&)>> m([](const SFoo& s1, const SFoo& s2) {
return s1.number < s2.number;
});
m.insert({ {"leon", 5}, "" });
m.insert({ {"leon", 4}, "" });
m.insert({ {"leon", 3}, "" });
m.insert({ {"leon", 2}, "" });
m.insert({ {"leon", 1}, "" });
m.insert({ {"ada", 5}, "" });
}
2、count()、count_if()
count()用来计算容器中与指定值相等的元素的个数,count_if()算法用来计算容器中符合指定条件元素的个数。
计算一个容器中元素长度小于5的元素个数,使用函数指针跟函数对象的话代码是这样子:
bool ShorterThanFun(const string& str)
{
return str.length() < 5;
}
int count = count_if(myVector.begin(), myVector.end(), ShorterThanFun);
class ShorterThan
{
public:
bool operator() (const string& str) const
{
return str.length() < 5;
}
};
int count = count_if(myVector.begin(), myVector.end(), ShorterThan());
如果我们要选取的元素的长度不是小于固定值5而是小于一个变量的话那么则只有使用函数对象能够完成,因为算法所使用的仿函数是固定参数的,而函数对象则可以通过它的构造函数来传入额外的参数,如下所示:
class ShorterThan
{
public:
explicit ShorterThan(int maxLength) : length(maxLength) {}
bool operator() (const string& str) const
{
return str.length() < length;
}
private:
const size_t length;
};
int count = count_if(myVector.begin(), myVector.end(), ShorterThan(length));
简而言之,使用函数对象相比函数来说提供了更多的操作和功能,比如可以传入参数给函数对象的构造函数,以供给函数对象中的operator()函数使用。
其实,使用bind的话会比上面的编码更方便,详见:http://www.cnblogs.com/milanleon/p/7491180.html。
3、find()、find_if()
find()算法用来查找与指定值相等的元素,它找到第一个相等的元素就返回其迭代器。find()使用的是operator==来判断元素与指定值是否相等,所以容器中元素如果是自定义类型的话还需要重载operator==。
class CItem {
public:
CItem(int n) { m_num = n; }
bool operator==(const CItem& item)const {
return this->m_num == item.m_num;
}
private:
int m_num = 0;
};
int main()
{
std::vector<CItem> v = { {101}, {100}, {103} };
auto iter = std::find(v.begin(), v.end(), CItem(100));
if (iter != v.end())
;
}
find_if()是find()的增强版本,它可以查找容器中符合指定条件的元素,其第三个参数就是一个函数或函数对象。
如下为查找容器中的第一个偶数元素,分别使用函数指针和函数对象:
#include <vector>
#include <algorithm>
bool IsEven(int i)
{
return ((i & 1) == 0);
}
class FindIf
{
public:
bool operator()(const int& i)
{
return ((i & 1) == 0);
}
};
int main()
{
std::vector<int> myvector;
myvector.push_back(15);
myvector.push_back(25);
myvector.push_back(30);
myvector.push_back(60);
auto it = std::find_if(myvector.begin(), myvector.end(), FindIf()/*IsEven*/);
if(it != myvector.end())
std::cout << "The first even value is " << *it << '\n';
return 0;
}
4、remove()、remove_if()
remove()用来"移除"与指定值相等的元素, 因为STL算法不能直接添加或删除元素,所以remove()其实并不删除元素只是将相等的元素移动到容器末尾,并返回指向末尾第一个移除元素的迭代器。所以一般我们是在remove()以后获得指向末尾第一个删除的元素的迭代器iter,然后再调用erase来真正删除这些元素:vc.erase(iter, vc.end()); remove()不能用于map或set ?需要注意的是调用remove()后返回的迭代器只能用于erase()来删除元素,不能再通过这个迭代器引用元素,因为迭代器中元素很有可能已经失效。
remove_if()是remove()的增强版,它能够移除符合指定条件的元素,它实际上是将所有应该移除的元素都移动到了容器尾部并返回一个分界的迭代器,所以还应该调用vector::erase(const_iterator first, const_iterator last)来删除这些区间中的元素。remove_if()不能用于map或set。需要注意的是调用remove()后返回的迭代器只能用于erase()来删除元素,不能再通过这个迭代器引用元素,因为迭代器中元素很有可能已经失效。
eg: 移除vector中大于10的元素:
#include <vector>
#include <algorithm>
bool GreaterThan(int& i)
{
return i > 10;
}
class CGreater
{
public:
bool operator()(int& i)
{
return i > 10;
}
};
int main()
{
int a[] = { 1, 3, 12, 15};
vector< int> arr(a, a + 4);
arr.erase(remove_if(arr.begin(), arr.end(), CGreater()/*GreaterThan*/), arr.end());
for (auto iter = arr.begin(); iter != arr.end(); iter++)
cout << *iter << endl;
return 0;
}
5、for_each()
for_each()对容器中的每个元素执行指定的操作,所以for_each()的函数对象的参数一般都是引用类型。如下为使用示例,分别使用函数指针和函数对象:
#include <vector>
#include <algorithm>
#include "boost/assign.hpp"
using namespace boost::assign;
void SquareFun(int& x)
{
x = x * x;
}
class Square
{
public:
void operator()(int& x)
{
x = x * x;
}
};
int main()
{
vector<int> v = list_of(1) (2) (3) (4);
for_each(v.begin(), v.end(), Square()/*SquareFun*/);
auto iter = v.begin(), iterEnd = v.end();
for (; iter != iterEnd; iter++)
cout << *iter << endl;
return 0;
}
6、transform
transform会对容器区间的每个元素进行指定的操作,与for_each()不同的是它可以将操作后的结果保存到另一个容器中,需要注意的是目标容器必须提前设置成合适的大小:
std::vector<int> foo = { 10, 20, 30 };
std::vector<int> bar;
bar.resize(foo.size()); //目标容器必须设置成合适的大小
//下面的transform使bar中元素为:11, 21, 31
std::transform(foo.begin(), foo.end()/*源容器*/, bar.begin()/*目标容器*/, [](int i) {
return ++i;
});
//下面的transform使foo中元素为:21, 41, 61
std::transform(foo.begin(), foo.end()/*源容器1*/, bar.begin()/*源容器2*/, foo.begin()/*目标容器*/, std::plus<int>() /*[](int n1, int n2) { return n1 + n2; }*/);
//利用transform将map转换成vector
std::map<int, int> m;
m.insert({ 100, 10 });
m.insert({ 200, 20 });
m.insert({ 300, 30 });
std::transform(m.begin(), m.end(), bar.begin(), [](auto& key_value) { return key_value.first; });
vector的resize()方法可以设置容器的大小,如resize(5)为将容器设置为包含5个元素的容器,对应的size()获得的就是当前容器大小,即容器中元素个数。 reserve()则设置的是预留空间大小,其对于容器的当前大小size()不影响,对应的capacity()获得的是当前预留空间的大小,推荐定义一个vector后调用reserve()来提前分配合理的预留空间以提高效率。
以下为transform与标准库函数toupper/tolower结合实现string的大小写转换的示例:
#include <algorithm>
#include <string>
#include <ctype.h>
int main()
{
std::string str = "abc";
std::transform(str.begin(), str.end(), str.begin(), toupper/*tolower*/);
//转换后str为ABC
return 0;
}
7、find()、search()、replace()
std::find():在指定范围内查找某个元素首次出现的位置,找到的元素位置可以通过iterFound - iterBegin获得。如果要从后往前找的话可以使用反向迭代器,找到的元素的位置通过iterRend - iterFound - 1获得
std::find_if():通过谓词指定查找的条件。
std::find_first_of(first1, last1, first2, last2):在[first1--last1)中查找[first2--last2)中元素首次出现的位置。
std::search(first1, last1, first2, last2):find只能查找一个元素,search()可以查找符合[first2, last2)的一段范围的值出现的位置,如果要从后面开始查找的话可以使用std::find_end()。
std::search_n(first, last, times, value):查找[first, last)中出现times次value值的位置。
std::replace():替换指定的元素
std::replace_if():根据谓词条件替换指定的元素
std::replace_copy:替换指定的元素,不改变原容器,将结果写入另一个容器中,写入的容器大小必须足够写入
std::replace_copy_if:根据谓词条件替换
8、max_element、min_element
max_element和min_element用来获得最大和最小值:
std::vector<int> vc{ 1, 2, 4, -4, 5, -5, -2, 2 };
auto it = std::max_element(vc.begin(), vc.end()
/*, [](int& n1, int& n2) { return n1 < n2; }*/
);
it = std::min_element(vc.begin(), vc.end()
/*, [](int& n1, int& n2) { return n1 < n2; }*/
);
9、求交集、并集、差集
求交集、并集、差集的容器必须是排好序的容器,比如set或者sort后的vector。
交集set_intersection(),使用示例①:
std::vector<std::string> vc = { "sh600000", "sz399000" };
std::list<std::string> lis = { "sh600000", "sz399001" };
//两个容器需要排好序
std::sort(vc.begin(), vc.end());
lis.sort();
//保存结果的容器需要提前申请大小
std::vector<std::string> vcResult;
vcResult.resize(vc.size() > lis.size() ? lis.size() : vc.size());
//结果集是有序的,默认使用<比较大小,也可以指定set_intersection()的第六个参数来设置排序方法
auto iter = std::set_intersection(vc.begin(), vc.end(), lis.begin(), lis.end(), vcResult.begin());
vcResult.resize(iter - vcResult.begin()); //调整结果容器大小,iter指向结果集的最后一个元素的下一位置
使用示例②:
#include <algorithm>
#include <iostream>
#include <iterator>
#include <vector>
int main()
{
std::vector<int> v1{7, 2, 3, 4, 5, 6, 7, 8};
std::vector<int> v2{5, 7, 9, 7};
std::sort(v1.begin(), v1.end());
std::sort(v2.begin(), v2.end());
std::vector<int> v_intersection;
std::set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(),
std::back_inserter(v_intersection));
}
使用示例③:
std::set<std::string> s1;
s1.insert("1");
s1.insert("2");
s1.insert("3");
s1.insert("4");
std::set<std::string> s2;
s2.insert("2");
s2.insert("3");
s2.insert("5");
std::set<std::string> s;
std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(), std::inserter(s, s.begin()));
并集set_union(),也可以使用std::inserter(),这样就不用提前申请空间了:
std::set<std::string> s1 = {"java", "c++", "python"};
std::set<std::string> s2 = {"c++", "c#"};
std::vector<std::string> vcUnion;
std::set_union(s1.begin(), s1.end(), s2.begin(), s2.end(), std::inserter(vcUnion, vcUnion.begin()));
差集set_difference():
结果集合中包含所有属于第一个集合但不属于第二个集合的元素。例如:集合{1,2,3,7,9}和{3,4,5,7}的差集为{1,2,9}。
对称差集set_symeetric_difference():去除同时出现在两个集合中的元素后,两集合其他元素组成的集合。例如:集合{1,2,3,7,9}和{3,4,5,7}的对称差为{1,2,4,5,9}。
10、累和
std::accumulate()可以求容器所有元素的累加和,对于string类型,相当于是拼接所有的元素,对于非内置类型的元素或者想自定义累加(拼接)结果,可以使用第四个参数,如下所示:
#include <numeric>
struct SFoo
{
std::string name;
int number;
};
int main(int argc, char** argv)
{
std::vector<int> vc = { 1, 2, 3 };
int sum = std::accumulate(vc.begin(), vc.end(), 100/*基数*/); // 106
std::vector<std::string> vc2 = { "1", "2", "3" };
std::string strSum = std::accumulate(vc2.begin(), vc2.end(), std::string("0")); // "0123"
SFoo ary[3] = { { "a", 1 }, { "b", 2 }, { "c", 3 } };
sum = std::accumulate(ary, ary + 3, 100, [](int a, SFoo b) { return a + b.number; }); // 106
strSum = std::accumulate(vc2.begin(), vc2.end(), std::string("0"), [](std::string s1, std::string s2) { return (s1 + "," + s2); }); //"0,1,2,3"
}
11、not1()、not2()
not1()是构造一个与谓词结果相反的一元函数对象,not2()是构造一个与谓词结果相反的二元函数对象:
#include <string>
#include <algorithm>
#include <functional>
#include <cctype>
int main(int argc, char** argv)
{
std::string s(" abc");
auto iter = std::find_if(s.begin(), s.end(), std::not1(std::function<int(int)>(std::isspace)));
s.erase(s.begin(), iter); // "abc"
}
12、一些其它常用方法:
std::list<int> l = { 1, 2, 3 };
std::vector<int> vc;
//使用copy()复制List容器中所有元素到vector
std::copy(l.begin(), l.end(), std::back_inserter(vc)/*std::back_insert_iterator<vector<int>>(vc)*/);
//使用copy()复制vector中内容到set
std::set<string> setRange;
const std::vector<std::string> vcRange = {"a", "b"};
std::copy(vcRange.begin(), vcRange.end(), std::inserter(setRange, setRange.begin())/*std::insert_iterator<std::set<std::string>>(setRange, setRange.begin())*/);
//equal()判断两个容器指定区间是否相同
bool b = std::equal(l.begin(), l.end(), vc.begin(), vc.end());
//fill()将容器指定区间元素都设置为某值
std::fill(vc.begin(), vc.end(), 100);
//count()获得容器中指定元素出现的次数
int n = std::count(vc.begin(), vc.end(), 100);
//lower_bound()获得升序排序容器中等于或大于指定值的元素的迭代器
std::list<int>::iterator it = std::lower_bound(l.begin(), l.end(), 4);
//swap()交换两个对象的值
int x = 10, y = 20;
std::swap(x, y); // x:20, y:10
std::vector<int> foo(4, x), bar(6, y);
std::swap(foo, bar); // foo:6x10,bar:4x20
//reverse()反转整个容器
std::vector<int> vcInt = { 3, 2, 1 };
std::reverse(vcInt.begin(), vcInt.end()); // 1, 2, 3
std::vector<int> vcDest;
vcDest.resize(vcInt.size());
std::reverse_copy(vcInt.begin(), vcInt.end(), vcDest.begin());
//vector的assign()方法可以重新初始化容器
std::vector<std::string> vcSource = {"abc", "def"};
std::vector<String> vcDest = {"123"};
vcDest.assign(vcSource.begin(), vcSource.end()); //vcDest : "abc", "def"
转载及参考出处:http://www.cnblogs.com/decade-dnbc66/p/5347088.html
13、迭代器:
c++中迭代器的类别有:前向迭代器(支持++it,it++)、双向迭代器(支持++it, it++, --it, it--)、随机访问迭代器(支持++it, it++, --it, it--, it+i, it-i, it[i])、输入迭代器和输出迭代器,其中输入/输出迭代器比较特殊,它们不是把数组或容器当做操作对象,而是把输入流/输出流作为操作对象。下面是不同容器中迭代器的类型:
以下为迭代器的定义方式:
std::vector<int> vc = { 1, 2, 3 };
std::vector<int>::iterator it = vc.begin();
std::vector<int>::const_iterator c_it = vc.begin();
std::next()相当于对迭代器进行+操作获得一个迭代器,std::prev相当于对迭代器进行-操作,std::advance()相当于对迭代器进行+=操作,std::distance()用来获得两个迭代器之间的距离。
迭代器适配器相当于是迭代器的“升级版”,下面为四种迭代器适配器,对反向迭代器进行++操作后迭代器会指向上一个元素。
如下为使用反向迭代器对vector进行逆序输出:
std::vector<int> vc = { 1, 2, 3 };
for (/*std::reverse_iterator<std::vector<int>::iterator> it = vc.rbegin()*/std::vector<int>::reverse_iterator it = vc.rbegin(); it != vc.rend(); ++it)
std::cout << *it << endl;
插入迭代器用来向容器插入元素,有以下三种类型:
下面是使用插入迭代器的示例:插入迭代器模板类中还对赋值运算符(=)进行了重载,我们可以使用=直接将新元素插入到目标容器:
std::vector<int> foo;
std::back_insert_iterator< std::vector<int> > back_it(foo);
back_it = 1; //将1插入到容器末尾
back_it = 2; //将2插入到容器末尾
back_it = 3; //将3插入到容器末尾
//使用copy()复制List容器中所有元素到vector
std::list<int> l = { 1, 2, 3 };
std::vector<int> vc;
std::copy(l.begin(), l.end(), std::back_inserter(vc)/*std::back_insert_iterator<vector<int>>(vc)*/);
//使用copy()复制vector中内容到set
std::set<string> setRange;
const std::vector<std::string> vcRange = {"a", "b", "c"};
std::copy(vcRange.begin(), vcRange.end(), std::inserter(setRange, setRange.begin())/*std::insert_iterator<std::set<std::string>>(setRange, setRange.begin())*/);
可以看到,使用std::transform()或std::copy()都可以将容器内容复制到另一个不同类型的容器,不同的是transform()中的目标容器必须先设置为合适的大小。