C++STL学习(8)迭代器

注:博客内容均来自于对《C++标准库》侯捷,华中科技大学出版社一书的笔记。转载请注明出处。

所有例程在Red Hat Linux 3.2.2-5版本上编译运行,g++的版本是 g++ (GCC) 3.2.2 20030222。


1、迭代器到底是什么?


  根据书上定义:迭代器是一种“能够遍历某个序列内所有元素”的对象。
我们可以将它理解成为一个指针,它指向容器中的元素,可以用它来遍历容器。迭代器是抽象的概念,任何有迭代器行为的对象都可以叫他迭代器


2、迭代器分类


迭代器可以分为:


1、Input迭代器


     Input迭代器只能一次一个向前读取元素,按此顺序一个个传回元素值。几乎所有的迭代器都有Input迭代器的能力。Input迭代器的各项操作如下表:




注:尽可能优先选用前置式递增运算符(++iter)而不是(iter++), 前置式的性能更好。

2、Output迭代器


Output迭代器和Input迭代器正好相反,其作用是将元素一个个写入。Output迭代器的各项操作如下表:





3、Forward迭代器


Forward迭代器是Inputd迭代器和Output迭代器的结合,具有Input迭代器的全部功能和Output迭代器的大部分功能。其功能如下表所示:



4、Random迭代器


支持Random迭代器的型别如下:
1> 可随机存取的容器(vector, deque)
2> strings (字符串, string, wstring)
3> 一般array (指针)
example:

#include <iostream>
#include <string>
#include <vector>
#include <deque>
#include <algorithm>

using namespace std;

void print(int elem)
{
	cout << elem << ' ';
}

int main()
{
	vector<int> col1;
	for(int i=0; i<9; ++i)
	{
		col1.push_back(i);
	}
	cout << "the source elements in the vector" << endl;
	for_each(col1.begin(), col1.end(), print);
	cout << endl << endl;
	vector<int>::iterator pos;
	cout << "iterator output:" << endl;
	for(pos = col1.begin(); pos!= col1.end(); ++pos)
	{
		cout << *pos << ' ';
	}
	cout << endl << endl;
	
	cout << "the reference output" << endl;
	for(int i=0; i<9; ++i)
	{
		cout << col1.begin()[i] << ' ';
	}
	cout << endl << endl;
	return 0;
}
运行结果:




3、迭代器相关辅助函数


1> advance() 迭代器前进(双向迭代器支持后退操作)


函数原型:
#include <iterator>
void advance (InputIterator& pos, Dist n)
使用实例:

#include <iostream>
#include <string>
#include <iterator>
#include <algorithm>

using namespace std;

int main()
{
	istream_iterator<string> cinPos(cin);
	ostream_iterator<string> coutPos(cout, " ");
	while(cinPos != istream_iterator<string>())
	{
		advance(cinPos, 2);
		if(cinPos != istream_iterator<string>())
		{
			*coutPos++ = *cinPos++;
		}		
	}
	cout<<endl;
	return 0;
}



2> distance() 计算迭代器之间的距离


函数原型:
#include <iterator>
Dist distance(InputIterator pos1, InputIterator pos2)
注:这里返回的型别Dist由迭代器决定:
example:
计算list<int>中两个迭代器的距离,则Dist返回的类型就是:
list<int>::difference_type
使用实例:


#include <iostream>
#include <list>
#include <algorithm>

using namespace std;

int main()
{
	list<int> col1;
	for(int i=0; i<9; ++i)
	{
		col1.push_back(i);
	}

	list<int>::iterator pos;
	pos = find(col1.begin(), col1.end(), 5);
		

	if(pos != col1.end())
	{
		list<int>::difference_type dis = distance(col1.begin(), pos);
		cout << "difference between beginning and 5: "
		<< dis << endl; 
	}
	else
	{
		cout << "5 not found! " << endl;
	}
	return 0;
}



3> iter_swap() 交换两个迭代器所指的内容


函数原型:
#include <algorithm>
void iter_swap(ForwardIterator pos1, ForwardIterator pos2)
注:迭代器的型别可以不同,但是所指的两个值必须能相互赋值!
使用实例:
#include <iostream>
#include <list>
#include <algorithm>
#include <iterator>

using namespace std;

int main()
{
	list<int> col1;
	for(int i=1; i<=9; ++i)
	{
		col1.push_back(i);
	}
	
	copy(col1.begin(), col1.end(), ostream_iterator<int>(cout, " "));
	cout << endl;

	iter_swap(col1.begin(), ++col1.begin());
	
	copy(col1.begin(), col1.end(), ostream_iterator<int>(cout, " "));
	cout<<endl;	

	iter_swap(col1.begin(), --col1.end());
	
	copy(col1.begin(), col1.end(), ostream_iterator<int>(cout, " "));
	cout<<endl;	

	return 0;
}





4、迭代器配接器


1> reverse迭代器 (逆向迭代器)


reverse迭代器重新定义递增运算和递减运算,使其行为正好倒置。

注:rbegin()和rend()分别传回容器中的最后一个位置和第一个元素前的位置。




2> insert迭代器(安插型迭代器)

insert迭代器用来向容器中安插元素。back insert, front insert, general insert 都属于insert迭代器。insert迭代器的种类入下表:

上述三种安插型迭代器分别举例子说明:

A.back insert 例子

      首先,来看back inserter的例子,这里使用vector容器,因为vector容器是支持push_back()操作的。这里只要选用支持push_back()操作的容器都是可以实现的。头文件print.h前面已经使用过的,为了方便查看,再次贴上。

print.h

#ifndef __PRINT_H
#define __PRINT_H


#include <iostream>

template <class T>
inline void PRINT_ELEMENTS (const T& col1, const char* optcstr="")
{
	typename T::const_iterator pos;
	std::cout << optcstr;
	for(pos = col1.begin(); pos != col1.end(); ++pos)
	{
		std::cout << *pos << ' ';
	}
	std::cout << std::endl;
}

#endif
main.cpp

#include <iostream>
#include <vector>
#include <algorithm>
#include "print.h"
using namespace std;

int main()
{
	vector<int> col1;
	//为col1创建一个后置配接器 --方式1
	back_insert_iterator<vector<int> > iter(col1);
	//使用后置配置节向col1插值
	*iter = 1;
	iter++;
	*iter = 2;
	iter++;
	iter = 3;
	PRINT_ELEMENTS(col1);
	
	//直接创建后置配接器并插值 --方式2
	back_inserter(col1) = 44;
	back_inserter(col1) = 55;
	PRINT_ELEMENTS(col1);
	
	//reserve足够空间以便后面的数据插入
	//reserve后col1中的值和迭代器均不改变
	col1.reserve(2*col1.size());
	PRINT_ELEMENTS(col1);
	
	//使用后置配接器
	copy(col1.begin(), col1.end(), back_inserter(col1));
	PRINT_ELEMENTS(col1);
	return 0;
}

B.front inerter 例子

由上表可以看到,front inserter 采用的是push_front()操作,这点要特别注意,因为vector是不支持push_front()操作的。所以这里选用list容器来实现。print.h不再贴出来浪费空间。

#include <iostream>
#include <list>
#include <algorithm>
#include "print.h"

using namespace std;

int main()
{
	list<int> col1;
	//为col1创建一个前置配接器   --方式1
	front_insert_iterator<list<int> > iter(col1);
	//使用配接器iter给col1插值
	*iter = 1;
	iter++;  //不移动iter也是可以的!!
	*iter = 2;
	iter++;
	iter = 3;
	PRINT_ELEMENTS(col1);
	
	//直接使用前置配接器给col1插值 --方式2
	front_inserter(col1) = 44;
	front_inserter(col1) = 55;
	PRINT_ELEMENTS(col1);
	
	//直接使用前置配接器插值
	copy(col1.begin(), col1.end(), front_inserter(col1));
	PRINT_ELEMENTS(col1);
}

C.普通inerter 例子

普通inserter的例子其实已经使用过,也随处可见。不过为了对比理解,贴上一例无妨。

#include <iostream>
#include <set>
#include <list>
#include <algorithm>
#include "print.h"

using namespace std;

int main()
{
	set<int> col1;
	//创建一个普通配接器   --方式1
	insert_iterator<set<int> > iter(col1, col1.begin());
	//使用定义好的配接器给容器插值
	*iter = 1;
	iter++;     //不移动iter也是可以的!!
	*iter = 2;
	iter++;
	iter = 3;
	PRINT_ELEMENTS(col1);
	
	//直接使用配接器给容器插值  --方式2
	inserter(col1, col1.end()) = 44;
	inserter(col1, col1.end()) = 55;
	PRINT_ELEMENTS(col1, "set:");
	
	list<int> col2;
	//使用配接器将col1中值逐次插入到col2的开始位置
	copy(col1.begin(), col1.end(), inserter(col2, col2.begin()));
	PRINT_ELEMENTS(col2, "list:");
	
	//使用配接器将col1中值逐次插入到col2第一个元素后
	copy(col1.begin(), col1.end(), inserter(col2, ++col2.begin()));
	PRINT_ELEMENTS(col2, "list:");
}

3> 流迭代器

A. ostream流迭代器


下面举个例子来说明ostream流迭代器的使用:

#include <iostream>
#include <vector>
#include <algorithm>
#include <iterator>

using namespace std;

int main()
{
	//创建一个输出流迭代器
	ostream_iterator<int> intWriter(cout, "\n");
	*intWriter = 42;
	intWriter++;     //不移动iter也是可以的!!
	*intWriter = 77;
	intWriter++;
	*intWriter = -5;
	
	vector<int> col1;
	for(int i=1; i<=9; ++i)
	{
		col1.push_back(i);
	}
	
	copy(col1.begin(), col1.end(), ostream_iterator<int>(cout));
	cout << endl;
	copy(col1.begin(), col1.end(), ostream_iterator<int>(cout," < "));
	cout<<endl;
	return 0;
}


B. istream流迭代器


同样,举例来说明istream的使用:

#include <iostream>
#include <iterator>

using namespace std;

int main()
{
	//创建一个读取int类型的输入流迭代器
	istream_iterator<int> intReader(cin);
	//创建一个结束流迭代器
	istream_iterator<int> intReadEOF;
	while(intReader != intReadEOF)
	{
		cout << "once: " << *intReader << endl;
		cout << "once again: "<< *intReader << endl;
		++intReader;
	}
}


5、实现一个迭代器

assoiter.h
#ifndef __ASSOITER_H
#define __ASSOITER_H

#include <iterator>

//继承自std::iterator<std::output_iterator_tag, void, void, void, void> 
//Container:容器型别 eg: set<int>
template<class Container>
class asso_insert_iterator 
	: public std::iterator <std::output_iterator_tag, 
							void, void, void, void> 
{
protected:
	Container& container;
public:
	explicit asso_insert_iterator (Container& c) : container(c)
	{
	}
	
	asso_insert_iterator<Container>& 
	operator= (const typename Container::value_type& value)
	{
		container.insert(value);
		return *this;
	}
	
	asso_insert_iterator<Container>& operator* ()
	{
		return *this;
	}
	
	asso_insert_iterator<Container>& operator++ ()
	{
		return *this;
	}
	
	asso_insert_iterator<Container>& operator++ (int)
	{
		return *this;
	}
};


template <class Container>
inline asso_insert_iterator<Container> asso_inserter (Container& c)
{
	return asso_insert_iterator<Container>(c);
}


#endif

assoiter.cpp
#include <iostream>
#include <set>
#include <algorithm>

#include "print.h"
#include "assoiter.h"

using namespace std;

int main()
{
	set<int> col1;
	asso_insert_iterator<set<int> > iter(col1);
	*iter = 1;
	iter++;     
	*iter = 2;
	iter++;
	iter = 3;
	PRINT_ELEMENTS(col1);
	asso_inserter(col1) = 44;
	asso_inserter(col1) = 55;
	PRINT_ELEMENTS(col1);
	
	int vals[] = {33, 67, -4, 13, 5, 2};
	copy(vals, vals+5, asso_inserter(col1));
	PRINT_ELEMENTS(col1);
	return 0;
}

至此,迭代器基本上就基本介绍完了。通过这些例子和迭代器的分类,得出结论:我们确实可以将它理解成为一个指针,它指向容器中的元素,可以用它来遍历容器,对容器进行操作,等等。






  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

空空的司马

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

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

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

打赏作者

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

抵扣说明:

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

余额充值