<<C++标准程序库>>中的STL简单学习笔记
0. 内容为个人学习笔记, 仅供参考, 如有错漏, 欢迎指正!
1. STL中的所有组件都是由模板构成的, 所以其元素可以是任意型别的. 组件有:
- 容器: 管理某类对象的集合. 不同的容器有各自的优缺点.
- 迭代器: 用来在一个对象集群(Collection of Objects) 的元素上进行遍历. 这个CoB可以是容器/容器的一部分. 每种容器都提供了自己的迭代器.
- 算法(Algorithm): 用来处理集群内的元素(比如: 查询,修改,排序等).
- 适配器(adapter)
- 仿函数(functors or function objects)
2. STL基本观念是将数据和操作分离, 数据交给容器进行管理, 操作(算法)可以定制算法, 使用迭代器来提供两者间统一的接口.
- STL 的概念有点儿和OOP的最初思想矛盾, 然而这个小框架提供了很好的容器/算法弹性.
- STL 是泛型编程的出色范例, 容器和算法对任意型别和类别而已已经一般化了.
- STL 提供了适配器和仿函数可以实现对算法的: 补充, 约束 和定制, 从而满足不同的需求.
3. 容器
- 序列式容器(Sequence container): 可序集群.(3个) ---- vector/deque/list (为什么queue,stack 和 string不是呢?)
- 可以将string 和 array 也当作是一种序列式容器(why?)
- array 是C/C++语言核心所支持的一个型别(type), 而不是(class). 具有静态大小和动态大小. 但它也并不是STL容器. 因为没有类似size(),empty()等成员函数. 但是STL的设计又允许它调用STL算法. 当我们以static arrays作为初始化行时特别有用.
- 没有必要直接编写dynamic array了, 因为可以用vector实现.
- 关联式容器(Association container): 已序集群(4个). 排序和元素值,插入顺序无关. ---- set/multiset/map/multimap
- 自动会对元素进行排序. 默认情况下是使用 operator < 进行比较.
- 一般关联容器由二叉搜索树实现 , 各容器的主要差别在于元素的类型已经处理重复元素的方式.
- set: 按内部元素的值进行排序, 不允许重复.
- multiset: 和set相同, 但允许重复
- map: key/values , 键不允许重复.
- multimap: 和map一样, 但键允许重复.可以用来当做字典.
4. 容器适配器
- stack: FILO
- queue: FIFO
- priority_queue: 下一个出队的元素永远是具有最高优先级的元素 ( 默认比较是 operator < 所以数值越小,优先级越高? ).
5. 迭代器(基本操作)
- operator */++/==/!=/=
- 每种容器都必须提供自己的内部类, 事实上每种容器都将其适配器定义为内部类.
- 任何一种容器都有2种类别的迭代器
- container::iterator
- container::const_iterator
6. 关联式容器的一些应用
- typedef set<int> IntSet; / typedef set<int, greater<int> >IntSet; greater<> 是一个预先定义的仿函数.
- 所有的关联容器都有一个insert()方法, 但是没有序列式容器的push_back(),push_front()方法 , 因为你没有权力指定新元素的位置.
- map 允许使用 operator [] 来安插元素. 而multimap不允许使用下标操作符(因为key可以重复哦).
- 存取multimap或map的元素时, 必须用pair结构的first和second成员才能访问到具体key/value
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main(){
typedef map<string,float> StringFloatMap;
StringFloatMap coll;
coll["VAT"] = 0.15;
coll["pi"] = 3.14;
coll["This is a string"] = 3.4;
coll["NULL"] = ;
StringFloatMap::iterator it = coll.begin(); // map 是不能手动排序,但是并不是没有序
for(;it!=coll.end();++it){ // 使用++it效率高于 it++
cout<<it->first<<" : "<<it->second<<endl;
}
return ;
}
7. 迭代器分类(2种)
- 双向迭代器(Bidirectional iterator): list/set/multiset/map/multiset提供的属于此类.
- 随机存取迭代器(Random access iterator): vector/deque/string提供的属于此类. 随机访问迭代器可以支持 operator <
8. 算法
- 不是容器的成员函数, 而是搭配迭代器使用的全局函数.
- pos = min_element(coll.begin(),coll.end()) / pos = max_element(coll.begin(),coll.end())
- sort(coll.begin(),coll.end()[,comp]);
- pos = find(coll.begin(),coll.end(),value);
- reserve(pos,coll.end())
- 处理多个区间
- equal(coll1.begin(),coll1.end(), coll2.begin() ); //必须设定第一个区间的起点和终点, 至于其他区间, 只需设置起点即可, 终点通常由第一区间的元素数量推断出来.
- copy(coll1.begin(),coll1.end(),coll2.begin()); //处理多个区间时注意区间的大小, 否则可能会读写到其他地方造成错误,如果不是STL安全版本不会有异常.
- 可以使用resize()改变目标容器的大小, 适用于序列式容器.
9. 迭代器适配器(Iterator Adapters)
- 迭代器是接口, 任何类别(class)只要具备这个接口就可以实现迭代. C++标准库提供了几个预定义的特殊迭代器, 即迭代器适配器(以下3种).
- Insert Iterator: 可以使算法以插入而非覆写的方式运作. 插入的位置(最前/最后/特定位置), 根据3重不同的Insert Iterator而异.
- back_inserter: copy(coll1.begin(),coll1.end(),back_inserter(coll2));
- 只有在提供push_back()的容器中才能用. (vector/deque/list)
- front_inserter: copy(coll1.begin(),coll1.end(),front_inserter(coll3));
- 容器要满足有push_front(). (deque/list)
- inserter: copy(coll1.begin(),coll1.end(),inserter(coll2,coll2.begin()); //只有inserter可以在关联容器上工作(非关联容器上应该也可以吧). 上面两种不行.
- 所有的STL容器都提供有insert(), 对于关联式容器而言, 提供一个开始搜寻的位置.
- Stream Interator: 一种用来读写流的迭代器, 提供了必要的抽象性, 使得来自键盘的输入像是个集群.
- copy(istream_iterator<string> (cin), istream_iterator<string>(), back_inserter(coll));
- istream_iterator<string>(cin) : 会产生一个从标准输入流cin读取数据的stream Iterator,读取string类型, 每当算法处理下一个元素时, 就转化为:cin>>string
- ostream_iterator<string>(): 调用istream iterator的default构造函数, 产生一个代表"流结束符"的迭代器.
- unique_copy(coll.begin(),coll.end(),ostream_iterator<string>(cout,"\n"));
- 第二个参数是可选的元素分隔符.
- Reverse Iterator: 提供逆向操作. 可以通过 rbegin()/rend()来产生逆向迭代器.
- copy(coll.rbegin(), coll.rend(), ostream_iterator<int>(cout," "));
- 可以将一般的迭代器转换为逆向迭代器, 反之亦然.
10. 更易型算法(manipulating algorithm)
- remove(): 移除元素, 但是容器的size(),返回的end() 没有改变, 因为是用容器后面的元素覆盖了删除的元素.
- remove()会返回删除元素后新的迭代器的位置, 而不改变原来容器迭代器的位置. list<int>::iterator end = remove(coll.begin(),coll.end(),value);
#include <iostream>
#include <map>
#include <string>
#include <iterator>
#include <list>
#include <algorithm>
using namespace std;
int main(){
list<int> coll; //list提供双向迭代器, 是双向链表.
for(int i=;i<=;++i){
coll.push_front(i);
coll.push_back(i);
}
copy(coll.begin(),coll.end(), ostream_iterator<int>(cout," "));
cout<<endl;
list<int>::iterator end = remove(coll.begin(),coll.end(),);
copy(coll.begin(),end,ostream_iterator<int>(cout," "));
cout<<endl;
cout<<distance(end,coll.end())<<endl;
coll.erase(end,coll.end());
copy(coll.begin(),coll.end(),ostream_iterator<int>(cout," "));
cout<<endl;
return ;
}
- 辅助函数 distance(), 返回迭代器之间的距离, 可以用于随机存取迭代器(还可以使用算术运算)和双向迭代器.
- coll.erase(end,coll.end()); 删除区间内的所有元素.
- 更易型算法不适用于关联式容器. 关联式的所有迭代器均被声明为指向常量. 更易关联式容器中的元素会产生编译错误.
- 不能使用算法函数 remove() 来移除关联式容器的元素, 但是可以通过调用关联式容器的方法erase()移除元素,返回被删除元素个数.
11. 算法函数和成员函数
- 容器本身可能提供功能相似算法函数而性能更佳的成员函数, 成员函数更了解具体容器的具体需要, 因此应该优先考虑成员函数.
- 有的容器操作, 使用成员函数和算法函数都可以. 但是成员函数性能更高.
12. 自定义泛型函数
13. 函数作为算法的参数
- 算法函数: for_each(coll.begin(),coll.end(), print) ;// print 是一个函数
std::transform(coll1.begin(),coll1.end(),std::back_inserter(coll2),square); //square 是一个函数
pos = find_if(coll.begin(),coll.end(), isPrime);
- 判断式
- 判断式通常用来指定排序准则和搜索准则, 不允许改变参数的状态. 如 isPrime
- 如果元素本身不支持 operator < ,那么一般会使用二元判断式(2个参数).
14. 仿函数(function object: 函数对象)
- 定义: 可以这么理解, 任何东西只要能像函数一样调用 , 就说它是个函数, 因此一般的对象如果重载了operator (), 那么就能像函数一样调用, 成为一个函数对象.
- 例子:
#include <iostream>
#include <map>
#include <string>
#include <iterator>
#include <list>
#include <algorithm>
#include <vector>
using namespace std;
class PrintInt{
public:
void operator()(int elem) const{
cout<<elem<<endl;
}
};
int main(){
vector<int> coll;
for(int i=;i<=;++i){
coll.push_back(i);
}
for_each(coll.begin(),coll.end(),PrintInt());
cout<<endl;
return ;
}
- 函数对象的优点:
- 是智能型函数:
- 函数对象有自己的类型, 可以拥有其他成员函数和成员变量, 意味着函数对象可以拥有状态.
- 可以在执行期间初始化它们.
- 每个函数对象有自己的型别:
- 一般函数只有当signature不同时才算型别不同, 而函数对象即使签名相同, 也可以有不同的类型.
- 可以设计仿函数继承体系, 完成其他事情.
- 仿函数比一办函数快
- 对template而言 , 更多的细节在编译期就已确定, 所以运行更佳.
- 例子
#include <iostream>
#include <iterator>
#include <list>
#include <algorithm>
using namespace std;
//function object that adds the value with witch it is initialized.
class AddValue{
private:
int theValue; // the value to add
public:
AddValue(int v):theValue(v){}
void operator()(int& elem) const{
elem += theValue;
}
}; int main(){
list<int> coll;
for(int i=;i<=;++i){
coll.push_back(i);
}
copy(coll.begin(),coll.end(),ostream_iterator<int>(cout," "));
cout<<endl;
for_each(coll.begin(),coll.end(),AddValue());
copy(coll.begin(),coll.end(),ostream_iterator<int>(cout," "));
cout<<endl;
for_each(coll.begin(),coll.end(),AddValue(*coll.begin()));
copy(coll.begin(),coll.end(),ostream_iterator<int>(cout," "));
cout<<endl;
return ;
}
- STL中预定义的仿函数
- less<int>() //默认的排序准则
- negate<int>(); // 处理数值, 转换为相反值. transform(coll.begin(),coll.end(),coll.begin(), negate<int>()); // 求相反数并回写.
- multiplies<int>(); // 处理数值, 相乘 transform(coll.begin(),coll.end(),coll.begin(),coll.begin(),multiplies<int>()); // 3个集群相同, 求的是平方, 保存回去.
- mem_fun_ref(&Person::save) //调用它所作用的元素的某个成员函数,参数可以是Person的派生类. for_each(coll.begin(), coll.end(), mem_fun_ref(&Person::save));
- 仿函数和适配器结合使用, 更加灵活; 而且这样这些仿函数都是inline, 性能更佳.
#include <iostream>
#include <iterator>
#include <set>
#include <queue>
#include <algorithm>
using namespace std; int main(){
// 可以在创建set的时候指定set内的排序规则.(?)
set<int,greater<int> > coll1; // 为什么不是 greater<int>()呢, greater不是一个类吗?
deque<int> coll2;
for(int i=;i<=;++i)
coll1.insert(i);
copy(coll1.begin(),coll1.end(),ostream_iterator<int>(cout," "));
cout<<endl;
//使用适配器 bind2nd() 将预先定义的仿函数和其他数值组合在一起.
// bind2nd会将10当成内部数值保存下来,当算法以实际集群元素为参数,
//调用bind2nd时, bind2nd会把该元素当成第一参数, 10当成第二参数,调用bind2nd的第一参数(仿函数).
transform(coll1.begin(),coll1.end(),back_inserter(coll2),bind2nd(multiplies<int>(),));//这里是multiplies<int>(),有括号呀?
copy(coll2.begin(),coll2.end(),ostream_iterator<int>(cout," "));
cout<<endl;
replace_if(coll2.begin(),coll2.end(),bind2nd(equal_to<int>(),),);
copy(coll2.begin(),coll2.end(),ostream_iterator<int>(cout," "));
cout<<endl;
coll2.erase(remove_if(coll2.begin(),coll2.end(), // range
bind2nd(less<int>(),)), // 删除标准
coll2.end());
copy(coll2.begin(),coll2.end(),ostream_iterator<int>(cout," "));
cout<<endl;
return ;
}
<<C++标准程序库>>中的STL简单学习笔记的更多相关文章
- Log4j简单学习笔记
log4j结构图: 结构图展现出了log4j的主结构.logger:表示记录器,即数据来源:appender:输出源,即输出方式(如:控制台.文件...)layout:输出布局 Logger机滤器:常 ...
- JavaSE中Collection集合框架学习笔记(2)——拒绝重复内容的Set和支持队列操作的Queue
前言:俗话说“金三银四铜五”,不知道我要在这段时间找工作会不会很艰难.不管了,工作三年之后就当给自己放个暑假. 面试当中Collection(集合)是基础重点.我在网上看了几篇讲Collection的 ...
- OI数学 简单学习笔记
基本上只是整理了一下框架,具体的学习给出了个人认为比较好的博客的链接. PART1 数论部分 最大公约数 对于正整数x,y,最大的能同时整除它们的数称为最大公约数 常用的:\(lcm(x,y)=xy\ ...
- JavaSE中Collection集合框架学习笔记(3)——遍历对象的Iterator和收集对象后的排序
前言:暑期应该开始了,因为小区对面的小学这两天早上都没有像以往那样一到七八点钟就人声喧闹.车水马龙. 前两篇文章介绍了Collection框架的主要接口和常用类,例如List.Set.Queue,和A ...
- Linux——帮助命令简单学习笔记
Linux帮助命令简单学习笔记: 一: 命令名称:man 命令英文原意:manual 命令所在路径:/usr/bin/man 执行权限:所有用户 语法:man [命令或配置文件] 功能描述:获得帮助信 ...
- 浏览器中js执行机制学习笔记
浏览器中js执行机制学习笔记 RiverSouthMan关注 0.0772019.05.15 20:56:37字数 872阅读 291 同步任务 当一个脚本第一次执行的时候,js引擎会解析这段代码,并 ...
- JavaSE中Collection集合框架学习笔记(1)——具有索引的List
前言:因为最近要重新找工作,Collection(集合)是面试中出现频率非常高的基础考察点,所以好好恶补了一番. 复习过程中深感之前的学习不系统,而且不能再像刚毕业那样死背面试题,例如:String是 ...
- JS和JQuery中的事件托付 学习笔记
事件托付事实上并非一个非常高级的技巧,比方在一个页面里面.当仅仅存在两个button的时候.可能你给button加入监听是这种:(本文不考虑浏览器兼容性.关于事件的兼容性可參考前面的学习笔记) < ...
- DFS中的奇偶剪枝学习笔记
奇偶剪枝学习笔记 描述 编辑 现假设起点为(sx,sy),终点为(ex,ey),给定t步恰好走到终点, s | | | + — — — e 如图所示(“|”竖走,“—”横走,“+”转弯),易证abs( ...
随机推荐
- java代码-------继承的方法----重写还是重载
总结:是自己不听讲吧,不懂啊 感觉父类的方法,子类可以重载,只要参数个数不同,重载与返回值没有关系 重写绝对是可以的.但答案是只能重写啊 package com.s.x; public class T ...
- ActiveMQ入门之四--ActiveMQ持久化方式
消息持久性对于可靠消息传递来说应该是一种比较好的方法,有了消息持久化,即使发送者和接受者不是同时在线或者消息中心在发送者发送消息后宕机了,在消息中心重新启动后仍然可以将消息发送出去,如果把这种持久化和 ...
- mybatis实现继承映射
ORM 框架的优势在于能让我们利用面向对象的思维去操作数据库, hibernate 作为重量级的 ORM 框架对面向对象的支持很强大.作为半自动化的 mybatis ,对面向对象的支持也是很完备的.这 ...
- 【BZOJ】1878: [SDOI2009]HH的项链 (主席树)
题目 传送门:QWQ 分析 莫队也能做,但我想练练主席树. 求k-th一样维护第i个时候的线段树,线段树来维护区间不同数. 然后查询时可以通过上下界小优化一波. 但是我的代码丑陋无比,常数巨大(捂脸 ...
- 显示本月日历demo
import java.text.DateFormatSymbols; import java.util.Calendar; import java.util.GregorianCalendar; p ...
- 排除maven jar冲突 maven tomcat插件启动报错 filter转换异常
最近在搞一个ssm+shiro的整合 用的maven tomcat插件 启动的时候报错,提示 maven org.springframework.web.filter.CharacterEncodin ...
- 基于OpenCV读取摄像头进行人脸检测和人脸识别
前段时间使用OpenCV的库函数实现了人脸检测和人脸识别,笔者的实验环境为VS2010+OpenCV2.4.4,opencv的环境配置网上有很多,不再赘述.检测的代码网上很多,记不清楚从哪儿copy的 ...
- mac 开启 chrome 和 微信开发者工具 跨域
微信开发者工具:open -n /Applications/wechatwebdevtools.app --args --disable-web-security --user-data-dir=/U ...
- 避免IE在ajax请求时,返回json出现下载
转自:https://blog.csdn.net/z521q1314/article/details/54409048
- Subversion Self Signed Certificates
When connecting to Subversion repositories using SSL connections the SVN client checks the server ce ...