C++迭代器与泛型算法(下)

迭代器再探

插入迭代器

是一种迭代器适配器。接受一个容器,生成一个迭代器,能实现向给定容器添加元素

  • back_inserter:使用push_back的迭代器,正向

  • front_inserter:使用push_front的迭代器,头插,反向

  • inserter:使用insert的迭代器,正向

    inserter迭代器的返回值仍为指向其本身的迭代器,与下面的代码相同

    inserter(it,it.begin());	//添加元素后it仍指向原来的元素
    //等价于:
    auto it=a.insert(it,val);	//此时it指向新添加的元素
    ++it;	//让it重新指向之前的元素
    

    使用copy算法复制容器

    	deque<int> a{ 1,2,3,4,5,6 };
    	list<int> b, c;
    	copy(a.cbegin(), a.cend(), front_inserter(b));
    	copy(b.cbegin(), b.cend(), inserter(c, c.begin()));
    

    使用unique_copy将不重复的元素拷贝到list:

    	vector<int> a{ 1,1,2,2,3,4,5,6,7,7,8,8,9,10 };
    	list<int> b;
    	sort(a.begin(), a.end());
    	unique_copy(a.cbegin(), a.cend(), inserter(b,b.begin()));
    

    各容器适用范围:

    vector:back_inserter inserter

    deque:全部适用

    list:全部适用

    forward_list:只适用front_inserter

流迭代器

istream_iterator操作

istream_iterator指定迭代器将要读的内容,因此要读取的类型必须定义了输入运算符>>

	istream_iterator<int> int_int(cin);		//从cin读取int
	istream_iterator<int> int_eof;			//尾后迭代器
	ifstream in("文件名.txt");
	istream_iterator<string> str_in(in);	//从文件读取string

PS:一个空的istream_iterator迭代器即是一个eof标记,可用作输入结束标记

从cin读取元素:

	vector<int> a;
	istream_iterator<int> int_int(cin);		//从cin读取int
	istream_iterator<int> eof_hhh;			//尾后迭代器,用做输入结束
	while (int_int != eof_hhh)	
	{		//istream_iterator读取数据 到vector 容器
		a.push_back(*int_int++);
	}

改写:一个比较牛逼的写法

	istream_iterator<int> int_int(cin),eof_hhh;
	vector<int> a(int_int, eof_hhh);		//从迭代器范围来构建对象,从cin读取,直到遇见eof

算法操作迭代器

	istream_iterator<int> int_int(cin),eof_hhh;
	cout << accumulate(int_int, eof_hhh, 0) << endl; //读取输入,自动求和

ostream_iterator操作

ostream_iterator指定迭代器将要输出的内容,因此要输出的类型必须定义了输出运算符<<

可以指定第二个参数:一个字符串字面常量或者字符数组的指针,表示在输出每个元素后都会打印此字符串

不允许空的ostream_iterator或表示尾后的ostream_iterator。

将元素写到cout

	ostream_iterator<int> out_iter(cout, " ");
	vector<int> a{ 1,2,3,4,5,6,7,8,9 };
	for (auto e : a)
	{
		*out_iter++ = e;	//实际上将e元素写到了cout
	}
	*out_iter = '\n';

在向ostream_iterator写入时,可以忽略 * 和 ++运算符,没有任何影响,但是不应该省略,为了清晰和理解。

比循环更简单的写法:

	ostream_iterator<int> out_iter(cout, " ");
	vector<int> a{ 1,2,3,4,5,6,7,8,9 };
	copy(a.cbegin(), a.cend(), out_iter);	//调用copy来使vector的每一个元素都写入到cout里去

示例

  1. 从一个文件读取string,写到vector< string >,并输出vector
	ifstream out_file("1.txt");		//打开文件
	istream_iterator<string> string_in(out_file),eof;	//定义输入和超尾迭代器
	ostream_iterator<string> out(cout, "\t");	//打印
	vector<string> a{ string_in,eof };		//根据迭代器构造容器
	copy(a.cbegin(), a.cend(), out);		//打印容器
  1. copy与输入输出的妙用:
	istream_iterator<int> in(cin), eof;
	ostream_iterator<int> out(cout, " ");
	vector<int> a;
	copy(in, eof, inserter(a, a.begin()));		//此copy可以给容器赋值
	sort(a.begin(), a.end());
	copy(a.cbegin(), a.cend(), out);			//此copy可以打印a的值
  1. 从文件读取整数,偶数放在一个文件,奇数放在一个文件,一个比较漂亮的写法:
	ifstream in_file("输入.txt");
	ofstream out_file1("输出1.txt"),out_file2("输出2.txt");
	istream_iterator<int> in(in_file), eof;
	vector<int> temp{ in,eof };
	ostream_iterator<int> out1(out_file1, "\n"), out2(out_file2, " ");
	//偶数在前,奇数在后
	auto iter=partition(temp.begin(),temp.end(), [](const int& num) {return num % 2);	 
	copy(temp.begin(), iter,out1);	//偶数
	copy(iter, temp.end(), out2);		//奇数

反向迭代器

就是在容器中从尾元素到首元素反向移动的迭代器。同时 ++ --等运算符的顺序也会相反。

除了forward_list之外,其他的容器都支持反向迭代器。

指向一个尾元素首元素的前一个元素。反向迭代器也有const和非const版本。

逆序打印容器中的元素:

	list<int> a{ 1,2,3,4,5,7,8,9 };
	for (auto r_iter = a.crbegin(); r_iter != a.crend(); ++r_iter)
	{
        //注意:反向变了,++也会执行相反的操作,++会往前移动。
		cout << *r_iter << " ";
	}

sort逆序排序容器元素:

sort(a.rbegin(), a.rend());

forward_list和流迭代器都不支持创建反向迭代器。

找到一个结束字符后,打印之前的内容:

	string temp{"woainiylh,wdada"};
	auto iter = find(temp.cbegin(), temp.cend(), ',');
	cout << string(temp.cbegin(), iter) << endl;		//正向打印 ‘,’之前的内容

如果我们采用反向打印:

	auto riter = find(temp.crbegin(), temp.crend(), ',');
	cout << string(temp.crbegin(), riter) << endl;		//反向打印 ‘,’之前的内容

我们很容易想到,结果一定使错误的,因为他会从尾部反向打印,元素顺序也会发生变化。

因此我们应该采用反向转正向的方式: base函数

	auto riter = find(temp.crbegin(), temp.crend(), ',');
	cout << string(riter.base(),temp.cend());	//base函数将反向迭代器转化为一个普通迭代器(正向)

注意迭代器的特性:左闭右开

示例:

  1. 使用reverse_iterator逆序打印一个vector:

    copy(a.crbegin(), a.crend(), out);
    
  2. 将一个有10个元素的vector的第3到第7个元素逆序拷贝到list中:

    	vector<int> a{ 1,2,3,4,5,6,7,8,9,10 };
    	list<int> b{ a.crbegin() + 3,a.crend() - 2 };	//第一种方法
    	/*auto it1 = find(a.cbegin(), a.cend(), 3);		//第二种方法
    	auto it2 = find(a.cbegin(), a.cend(), 7);
    	copy(it1, it2+1, front_inserter(b));*/
    	for_each(b.cbegin(), b.cend(), [](const int& num) {cout << num << " "; });
    

泛型算法结构

五类迭代器类型

  1. 输入迭代器:只读,只能递增

    ​ 关系运算符,递增运算符,解引用运算(只出现在赋值运算符的右侧),箭头运算符

    单遍扫描算法:find accumulate 算法;istream_iterator就是一个输入迭代器。

  2. 输出迭代器:只写,只能递增

    ​ 递增运算符,解引用运算(只出现在赋值运算符的左侧)

    单遍扫描算法:copy算法;ostream_iterator就是一个输出迭代器。

  3. 前向迭代器:可读写,只能递增

    ​ 支持输入输出的所有操作

    多遍扫描:replace算法;forward_list上的迭代器是前向迭代器。

  4. 双向迭代器:可读写,可以递增递减

    ​ 支持输入输出和前向的所有操作

    多遍扫描:reverse算法;除了forward_list之外,标准库都提供符合双向迭代器要求的迭代器

  5. 随机访问迭代器:可读写,支持全部迭代器运算

    ​ 支持输入输出前向和双向的所有操作

    多遍扫描:sort算法;array deque string vector的迭代器都是随机访问迭代器

算法形参模式

  • arg(beg,end,other):一个范围,一个其他操作
  • arg(beg,end,dest,other):一个范围,一个目标,一个其他操作
  • arg(beg1,end1,beg2,other):一个范围,一个目标起点,一个其他操作
  • arg(beg1,end1,beg2,end2,other):一个范围,一个目标范围,一个其他操作

算法的命名

同一算法可以重载为接受谓词

unique(beg,end); 使用默认==

unique(beg,end,comp); 使用定义的comp


_if版本的算法

同样是一个接受谓词的版本:

find(beg,end,val) 查找val第一次出现

fin_if(beg,end,pred) 查找pred函数为真的位置


拷贝元素的版本: 将重排后的序列拷贝到新的序列

reverse 和 reverse_copy

remove_if 和 remove_copy_if

特定容器的算法

list(双向迭代器)和forward_list(前向迭代器)由于不支持随机访问,因此他们有自定义的成员函数:

sort ,merge , remove ,reverse , unique

1:sort()需要随机访问迭代器,所以不能用于list和forward_list.

2:对于list和forward_list应优先使用其成员函数版本的算法,皆返回void.

3:remove()删除元素,reverse()反转元素顺序,sort()排序,unique()删除相同元素

4:链表类型还定义了splice成员算法,其实链表数据结构所特有的,主要用于合并两个链表

使用list实现重复单词去重:

list<string> a;
string temp;
while (cin >> temp)
{
	a.push_back(temp);
}
a.sort();
a.unique();
for_each(a.cbegin(), a.cend(), [](const string& s) {cout << s << " "; });
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Yuleo_

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值