关于c++的STL的学习与再认识(二)
2015-07-29 11:14
417 查看
接上一篇文章。
上一篇文章讲到了容器以及vector,以及相关的函数,比如vector的初始化方法,size(),resize(),push_back(),empty(),clear(),以及对于vector的按值传递和引用传递。
这一篇文章介绍键值对和非常重要的迭代器。
普通的pair(int, int)就是一个整型值。比较复杂的是pair(string,pair(int, int))。第二种情况可以这么用:
键值对的优势在于有内置操作来比较pair对象。键值对优先对比第一个元素值,相等时才比较第二个元素值。若不想等,结果就只取决于第一个元素之间的比较。对此,可以轻易的对数据(或vector)进行排序。
关联容器中广泛使用pair。
迭代器定义的操作:
- 从迭代器取值: int n = *it;
- 让迭代器自增自减:it++,it–;
- 比较:it1 != it2; it1 < it2;
- 向迭代器添加一个常量值:it+=20(向前移动了20个元素位置)
- 获取量迭代器之间的差值:int n = it2 - it1;
迭代器的最大优势是极大的增加了代码重用性:基于迭代器写的算法在大部分的容器上都能使用。
比如翻转数组的算法:
这种函数原型叫做模板:只是声明函数的一种方式,对任何恰当的参数类型都是有效的。
STL常用的两个迭代器:begin和end。需要注意的是,尾部迭代器并不是指向最后一个对象,而是指向第一个无效对象,或者是紧跟在最后一个对象后面的对象。begin()和end()分别返回容器的初始和尾部迭代器。
当容器c为空时,c.begin() == c.end()才为真。而c.end() - c.begin()总是等于c.size().(只有能做减法式才成立)
兼容STL的翻转函数:
此函数功能与标准函数:std::reverse(T begin, T end)的功能一一样(使用时包含**#include).
下面举例子说明:
上面例子可以知道:
1. 可以用一个数组的下标范围初始化vector
2. 函数rbegin()和rend()返回反向迭代器(与正常迭代器的指向相反)。
要创建一个迭代器对象, 必须要指定类型。在容器类型的后面加上“::iterator, ::const_iterator, ::reverse_iterator, ::const_reverse_iterator”就可以构建迭代器的类型。如下:
推荐使用!= 而不是<,使用empty()而不是size()!=0。对于某些容器类型来说,无法高效的确定迭代器的前后顺序。
STL算法的声明方式相同:以一对迭代器(一个范围的初始迭代器和尾部迭代器),并放回一个迭代器。
fInd()算法:在一个区间内寻找合适的元素,找到则返回指向第一个匹配元素的迭代器。否则,返回的值指向区间的尾部。要找到元素的下标,用find()返回值减去初始迭代器。
min_element()和max_element();
现在,可以定义有效的宏定义:
注意:all(v)后面没有括号。
上一篇文章讲到了容器以及vector,以及相关的函数,比如vector的初始化方法,size(),resize(),push_back(),empty(),clear(),以及对于vector的按值传递和引用传递。
这一篇文章介绍键值对和非常重要的迭代器。
STL:标准模板库(Standard Template Library—STL)
键值对:
在了解迭代器之前,先了解一下键值对。STL中的std::pair就是一个键值对,简单形式如下:template<typename T1, typename T2> struct pair { T1 first; T2 second; };
普通的pair(int, int)就是一个整型值。比较复杂的是pair(string,pair(int, int))。第二种情况可以这么用:
pair<string, pair<int,int> > P; string s = P.first; // extract string int x = P.second.first; // extract first int int y = P.second.second; // extract second int
键值对的优势在于有内置操作来比较pair对象。键值对优先对比第一个元素值,相等时才比较第二个元素值。若不想等,结果就只取决于第一个元素之间的比较。对此,可以轻易的对数据(或vector)进行排序。
关联容器中广泛使用pair。
迭代器
迭代器:访问容器数据结构的最普通的方式。拥有以下四种操作:取值(*),对比(<,!=),自增(++),自减(–)。并且和容器相关联的对象就叫做迭代器。任何STL容器都可以通过迭代器遍历。迭代器定义的操作:
- 从迭代器取值: int n = *it;
- 让迭代器自增自减:it++,it–;
- 比较:it1 != it2; it1 < it2;
- 向迭代器添加一个常量值:it+=20(向前移动了20个元素位置)
- 获取量迭代器之间的差值:int n = it2 - it1;
迭代器的最大优势是极大的增加了代码重用性:基于迭代器写的算法在大部分的容器上都能使用。
比如翻转数组的算法:
template<typename T> void reverse_array(T *first, T *last) { if(first != last) { while(true) { swap(*first, *last); first++; if(first == last) { //用<代替== break; } last--; if(first == last) { break; } } }
这种函数原型叫做模板:只是声明函数的一种方式,对任何恰当的参数类型都是有效的。
STL常用的两个迭代器:begin和end。需要注意的是,尾部迭代器并不是指向最后一个对象,而是指向第一个无效对象,或者是紧跟在最后一个对象后面的对象。begin()和end()分别返回容器的初始和尾部迭代器。
当容器c为空时,c.begin() == c.end()才为真。而c.end() - c.begin()总是等于c.size().(只有能做减法式才成立)
兼容STL的翻转函数:
template<typename T> void reverse_array_stl_compliant(T *begin, T *end) { // We should at first decrement 'end' // But only for non-empty range if(begin != end) { end--; if(begin != end) { while(true) { swap(*begin, *end); begin++; If(begin == end) { break; } end--; if(begin == end) { break; } } } } }
此函数功能与标准函数:std::reverse(T begin, T end)的功能一一样(使用时包含**#include).
下面举例子说明:
int n[] = { 11, 22, 33, 44, 55, 66, 77, 88, 99 }; vector<int> v1(n, n + 9); print(v1); // 11, 22, 33, 44, 55, 66, 77, 88, 99 vector<int> v2(v1.begin(), v1.begin() + v1.size() / 2); print(v2); // 11, 22, 33, 44 reverse(v1.begin() + 2, v1.begin() + 5); print(v1); //11, 22, 55, 44, 33, 66, 77, 88, 99 vector<int> v3(v1.rbegin(), v1.rend()); print(v3);//99, 88, 77, 66, 55, 44, 33, 22, 11
上面例子可以知道:
1. 可以用一个数组的下标范围初始化vector
2. 函数rbegin()和rend()返回反向迭代器(与正常迭代器的指向相反)。
要创建一个迭代器对象, 必须要指定类型。在容器类型的后面加上“::iterator, ::const_iterator, ::reverse_iterator, ::const_reverse_iterator”就可以构建迭代器的类型。如下:
int n[] = { 11, 22, 33, 44, 55, 66, 77, 88, 99 }; vector<int> v1(n, n + 9); for (vector<int>::iterator it = v1.begin(); it != v1.end();it++) { cout << *it << " "; // 11, 22, 33, 44, 55, 66, 77, 88, 99 }
推荐使用!= 而不是<,使用empty()而不是size()!=0。对于某些容器类型来说,无法高效的确定迭代器的前后顺序。
STL算法的声明方式相同:以一对迭代器(一个范围的初始迭代器和尾部迭代器),并放回一个迭代器。
fInd()算法:在一个区间内寻找合适的元素,找到则返回指向第一个匹配元素的迭代器。否则,返回的值指向区间的尾部。要找到元素的下标,用find()返回值减去初始迭代器。
int n[] = { 11, 22, 33, 44, 55, 66, 77, 55, 99 }; vector<int> v1(n, n + 9); cout << find(v1.begin(), v1.end(), 55) - v1.begin() << endl;// 4 cout << find(v1.begin(), v1.end(), 98) - v1.begin() << endl;// 9
min_element()和max_element();
int n[] = { 22, 33, 11, 44, 55, 66, 99, 55, 88 }; vector<int> v1(n, n + 9); cout << *max_element(v1.begin(), v1.end()) << endl; // 99 cout << *min_element(v1.begin(), v1.end()) << endl; // 11 cout << max_element(v1.begin() , v1.end()) - v1.begin() << endl; // 6 cout << min_element(v1.begin() , v1.end()) - v1.begin() << endl; //2
现在,可以定义有效的宏定义:
define all(v) (v).begin(), (v).end()
注意:all(v)后面没有括号。
int n[] = { 22, 33, 11, 44, 55, 66, 99, 55, 88 }; vector<int> v1(n, n + 9); //sort(v1.begin(), v1.end()); //11, 22, 33, 44, 55, 66, 77, 88, 99 //sort(all(v1)); //11, 22, 33, 44, 55, 66, 77, 88, 99 sort(v1.rbegin(), v1.rend()); //99, 88, 77, 66, 55, 44, 33, 22, 11 print(v1);
相关文章推荐
- 设计模式之行为型模式 - 调用行为的传递问题
- [div+css]晒晒最新制作专题推广页模板
- 2008大学生入党申请书 模板
- Ruby中的迭代器详解
- Ruby中Block和迭代器的使用讲解
- Lua中的迭代器浅析
- Lua中的迭代器和泛型for介绍
- IMAIL多语言模板两套Outlook&Gmail模板下载
- C#特性-迭代器(上)及一些研究过程中的副产品
- C#迭代器模式(Iterator Pattern)实例教程
- 在PHP中使用模板的方法
- 深入解析php模板技术原理【一】
- Lua中的迭代器和泛型for学习总结
- Json2Template.js 基于jquery的插件 绑定JavaScript对象到Html模板中
- 在ASP中不用模板生成HTML静态页直接生成.html页面
- C#模板方法模式(Template Method Pattern)实例教程
- C#特性 迭代器(下) yield以及流的延迟计算
- ruby 迭代器使用方法
- 关于Asp代码与页面的分离模板技术第1/3页
- 测试开始与结束通知邮件模板