笔记会持续更新,有错误的地方欢迎指正,谢谢!
再探迭代器
除了前面介绍的标准库容器迭代器外,C++还在头文件iterator中定义了额外的集中迭代器:
- 插入迭代器:绑定到容器上,可用来向容器中插入元素。
- 流(iostream)迭代器:绑定到输入输出流上,可用来遍历所关联的IO流。
- 反向迭代器:跟普通的迭代器方向相反(forward_list没有这个,你懂得)。
- 移动迭代器:是移动元素而不是拷贝元素(是不是很诱人~以后再详细介绍)。
插入迭代器
有三种:
back_inserter, inserter,front_inserter
插入迭代器:back_inserter、inserter、front_inserter分别调用容器操作push_back、insert、push_front。
vector<int> vec;
auto it = back_inserter(vec);
*it = 0; //{0},尾插
auto is = front_inserter(vec);
*is = -1; //{-1, 0},头插
list<int> lst1 = {1, 2, 3};
list<int> lst2;
copy(lis1.cbegin(), lst1.cend(), inserter(lst2, lst2.begin()) ); //lst2拷贝了lst1
流迭代器
虽然iostream不是容器,但标准库还是定义了这些类型对象的迭代器。istream_iterator读取输入流,ostream_iterator向一个输出流写数据。
流迭代器将它们对应的流当作一个特定类型的元素序列(类似容器)来处理。通过使用流迭代器,我们可以使用泛型算法从流对象读取数据以及向其写入数据 。
下面是一个用istream_iterator从标准输入读取数据,存入一个vector的例子:
istream_iterator<int> in_iter(cin); //从cin读取int
istream_iterator<int> eof; //空的istream_iterator当作istream尾后迭代器
while(in_iter != eof)
{
vec.push_back(*in_iter++);//先对in_iter解引用后,最后才把in_inter自增1。
}
我们来个牛逼的写法:
istream_iterator<int> in_iter(cin), eof;
vector<int> vec(in_iter, eof);
这两行代码和上面的程序完全等价:我们用一对元素范围的迭代器来构造vec,这个构造函数通过in_iter从cin中读取数据,直到遇到文件尾或者遇到不是int的数据为止,从流中读取的数据用于构造vec。
再来个酷炫的,输入数据求和:
istream_iterator<int> in(cin), eof;
cout << accumulate(in, eof, 0) << endl; //从标准输入中读取数值求和输出
补充:如果两个istream_iterator都是尾后迭代器或绑定到相同的输入则相等。
反向迭代器
来个例子,逆序打印vec中的元素:
vector<int> vec = {1, 2, 3};
for(auto r_iter = vec.crbegin(); r_iter != vec.crend(); ++r_iter)
{
cout << *r_iter << endl;
}
使用反向迭代器的时候,要注意的就是+ +和- -时的前进方向。
不懂的看下图:
泛型算法结构
都是对之前一些细节的总结,就不说了,没什么实质内容。
特定容器算法-链表list和forward_list
与其他容器不同,链表定义了独有的一些函数:sort(), merge(), remove(), reverse()和unique(),可改变底层容器,优先使用它们而不是通用算法。因为通用的sort()要求随机访问迭代器,因此不能用于链表,链表要用双向迭代器或前向迭代器。
函数说明:
函数 | 含义 |
---|---|
lst.merge(lst2)(重载版:lst.merge(lst, comp)) | 将lst2的元素并入lst中,二者原先必须是有序的。第一个版本使用的是<运算符;第二个版本使用自定义比较操作。合并后,lst2变为空。 |
lst.remove(val)(重载版:lst.remove_if(pred)) | 函数会调用erase()删除与val相等或使一元谓词pred为真的所有元素。 |
lst.reverse() | 翻转lst的元素顺序。 |
lst.sort()(重载版:lst.sort(comp)) | 使用<或自定义比较操作排序元素。 |
lst.unique()(重载版:lst.unique(pred)) | 调用erase()删除同一个值的连续拷贝。第一个版本使用==,第二个版本使用给定的二元谓词 |
splice成员:链表特有的算法,将一个链表的一截移动到另一个链表的指定位置,要保证移动的目的位置不在待移动范围内