STL中体现了泛型化程序设计的思想
一、STL包含
1、标准STL序列容器:vector、string、deque和list。
2、标准STL关联容器:set、multiset、map和multimap。
3、非标准序列容器slist和rope。slist是一个单向链表,rope本质上是一个重型字符串。(“绳子
(rope)”是重型的“线(string)”。明白了吗?)你可以找到一个关于这些非标准
(但常见的)容器的概览在条款50。
4、非标准关联容器hash_set、hash_multiset、hash_map和hash_multimap。我在条款25检验了这些 可以广泛获得的基于散列表的容器和标准关联容器的不同点。
5、STL迭代器
6、算法
7、适配器
二、详解
1)序列容器
1、Vector:将元素置于一个动态数组中加以管理,可以随机存取元素(用索引直接存取),
数组尾部添加或移除元素非常快速。但是在中部或头部安插元素比较费时;
--是一块连续内存,当空间不足了会再分配。 需要动态增加的能力,侧重于寻找数据的速度
(1)头文件#include<vector>.
(2)创建vector对象,vector<int> vec;
(3)使用下标访问元素,cout<<vec[0]<<endl;记住下标是从0开始的。
(4)使用迭代器访问元素.
vector<Type>::iterator iter = vec.begin();
for ( ; iter != vec.end(); iter++)
{
cout << *iter <<endl;
}
1.push_back 在数组的最后添加一个数据,vec.push_back(a);
2.pop_back 去掉数组的最后一个数据 ,vec.pop_back(a);
3.at 得到编号位置的数据
4.begin 得到数组头的指针
5.end 得到数组的最后一个单元+1的指针
6.front 得到数组头的引用
7.back 得到数组的最后一个单元的引用
8.max_size 得到vector最大可以是多大
9.capacity 当前vector分配的大小
10.size 当前使用数据的大小
11.resize 改变当前使用数据的大小,如果它比当前使用的大,者填充默认值;设置大小(size);
12.reserve 改变当前vecotr所分配空间的大小;设置容量(capacity);capacity()只是设置容器容量大小,但并没有真正分配内存。
13.erase 删除指针指向的数据项
14.clear 清空当前的vector
15.rbegin 将vector反转后的开始指针返回(其实就是原来的end-1)
16.rend 将vector反转构的结束指针返回(其实就是原来的begin-1)
17.empty 判断vector是否为空
18.swap 与另一个vector交换数据
http://blog.youkuaiyun.com/hancunai0017/article/details/7032383
2、deque(双端队列):可以随机存取元素(用索引直接存取),数组头部和尾部添加或移除元素都非
常快速。但是在中部或头部安插元素比较费时;
--即需要前后增删数据的能力,又要良好的数据访问速度
1.Constructors 创建一个新双向队列
语法:
deque();//创建一个空双向队列
deque( size_type size );// 创建一个大小为size的双向队列
deque( size_type num, const TYPE &val ); //放置num个val的拷贝到队列中
deque( const deque &from );// 从from创建一个内容一样的双向队列
deque( input_iterator start, input_iterator end );
// start 和 end - 创建一个队列,保存从start到end的元素。
2.Operators 比较和赋值双向队列
//可以使用[]操作符访问双向队列中单个的元素
3.assign() 设置双向队列的值
语法:
void assign( input_iterator start, input_iterator end);
//start和end指示的范围为双向队列赋值
void assign( Size num, const TYPE &val );//设置成num个val。
4.at() 返回指定的元素
语法:
reference at( size_type pos ); 返回一个引用,指向双向队列中位置pos上的元素
5.back() 返回最后一个元素
语法:
reference back();//返回一个引用,指向双向队列中最后一个元素
6.begin() 返回指向第一个元素的迭代器
语法:
iterator begin();//返回一个迭代器,指向双向队列的第一个元素
7.clear() 删除所有元素
8.empty() 返回真如果双向队列为空
9.end() 返回指向尾部的迭代器
10.erase() 删除一个元素
语法:
iterator erase( iterator pos ); //删除pos位置上的元素
iterator erase( iterator start, iterator end ); //删除start和end之间的所有元素
//返回指向被删除元素的后一个元素
11.front() 返回第一个元素的引用
12.get_allocator() 返回双向队列的配置器
13.insert() 插入一个元素到双向队列中
语法:
iterator insert( iterator pos, size_type num, const TYPE &val ); //pos前插入num个val值
void insert( iterator pos, input_iterator start, input_iterator end );
//插入从start到end范围内的元素到pos前面
14.max_size() 返回双向队列能容纳的最大元素个数
15.pop_back() 删除尾部的元素
16.pop_front() 删除头部的元素
17.push_back() 在尾部加入一个元素
18.push_front() 在头部加入一个元素
19.rbegin() 返回指向尾部的逆向迭代器
20.rend() 返回指向头部的逆向迭代器
21.resize() 改变双向队列的大小
22.size() 返回双向队列中元素的个数
23.swap() 和另一个双向队列交换元素
3、List:双向链表:双向链表,不提供随机存取(按顺序走到需存取的元素,O(n)),在任何位置上执行
插入或删除动作都非常迅速,内部只需调整一下指针;insert(iter, param)
--list - 需要动态增加的能力,侧重于增加删除数据的速度:
一种是基本的ArrayList,其优点在于随机访问元素,另一种是更强大的LinkedList,它并不是
为快速随机访问设计的,而是具有一套更通用的方法。
4、String:string提供增加、删除、查找、替换等操作,非常方便。
1 基本用法
(1)头文件#include<string>
(2)直接赋值,string str="Hello my dear";
把字符指针赋值给string对象:char ss[30]="my name"; string str=ss;
(3)尾部追加:string str="hello"; str+='a';(加字符)str+="aa";(加字符串);
str.append("aaa");(方法追加)
(4)插入字符:string str="12345";string::iterator it=str.begin();
str.insert(it+1,'a');//在第1个元素前插入(从0开始)
(5)访问:string str="1234";cout<<str[0]<<str[1]<<endl;
(6)删除:string str="123456";string::iterator it=str.begin();str.erase(it);删除‘1’
str.erase(it+1,it+2);//把‘3’删除了
(7)长度str.length();判断是否为空str.empty();
(8)替换:str.replace(i,len,"aaaa");//从第i开始,连续len个字符替换为"aaaa";公有10个
重载版本,这是最常用的。
(9)查找:int i=str.find("aaa");查找"aaa"在str中的位置,找不到返回string::npos;
(10)比较str.compare("aaa");如果str<"aaa",返回-1;
str=="aaa",返回0;str>"aaa",返回1
(11)翻转,加头文件#include<algorithm> ; reverse(str.begin(),str.end());
2 string 与数字转换
如果string中存放数字,可以通过遍历处理每一位数字
for(i=0;i<str.length();i++) 对str[i]处理(如求每一位的和,转为整数等)
2)关联容器
1、Set/Multiset:内部的元素依据其值自动排序,Set内的相同数值的元素只能出现一次,
Multisets内可包含多个数值相同的元素,内部由二叉树实现(实际上基于红黑树(RB-tree)实现),
便于查找;
因为是排序的,所以set中的元素不能被修改,只能删除后再添加。
首先set,不像map那样是key-value对,它的key与value是相同的。
关于set有两种说法,第一个是STL中的set,用的是红黑树;第二个是hash_set,底层用得是hash
table。红黑树与hash table最大的不同是,红黑树是有序结构,而hash table不是。但不是说set
就不能用hash,如果只是判断set中的元素是否存在,那么hash显然更合适,因为set 的访问操作
时间复杂度是log(N)的.
1.begin() ,返回set容器的第一个元素
2.end() ,返回set容器的最后一个元素
3.clear() ,删除set容器中的所有的元素
4.empty() ,判断set容器是否为空
5.max_size() ,返回set容器可能包含的元素最大个数
6.size() ,返回当前set容器中的元素个数
7.rbegin ,返回的值和end()相同
8.rend() ,返回的值和rbegin()相同
9.count() 用来查找set中某个某个键值出现的次数。
10.equal_range() ,返回一对定位器,分别表示第一个大于或等于给定关键值的元素和 第一个大于给定关键值的元素,这个返回值是一个pair类型,如果这一对定位器中哪个返回失败,就会等于end()的值。
12.erase(iterator) ,删除定位器iterator指向的值
13.erase(first,second),删除定位器first和second之间的值
14.erase(key_value),删除键值key_value的值
15.find() ,返回给定值值得定位器,如果没找到则返回end()。
16.insert(key_value); 将key_value插入到set中 ,返回值是pair<set<int>::iterator,bool>,bool标志着插入是否成功,而iterator代表插入的位置,若key_value已经在set中,则iterator表示的key_value在set中的位置。
17.inset(first,second);将定位器first到second之间的元素插入到set中,返回值是void.
18.lower_bound(key_value) ,返回第一个大于等于key_value的定位器
19.upper_bound(key_value),返回最后一个大于等于key_value的定位器
#include <iostream>
#include <set>
using namespace std;
int main()
{
set<int> s;
s.insert(1);
s.insert(2);
s.insert(3);
s.insert(1);
cout<<"set 的 size 值为 :"<<s.size()<<endl;
cout<<"set 的 maxsize的值为 :"<<s.max_size()<<endl;
cout<<"set 中的第一个元素是 :"<<*s.begin()<<endl;
cout<<"set 中的最后一个元素是:"<<*s.end()<<endl;
s.clear();
if(s.empty())
{
cout<<"set 为空 !!!"<<endl;
}
cout<<"set 的 size 值为 :"<<s.size()<<endl;
cout<<"set 的 maxsize的值为 :"<<s.max_size()<<endl;
return 0;
}
2、Map/Multimap:map和multimap将key和value组成的pair作为元素,根据key的排序准则自动将元素
排序,map中元素的key不允许重复,multimap可以重复。内部由二叉树实现(实际上基于红
黑树(RB-tree)实现),便于查找;
因为是排序的,所以map中元素的key不能被修改,只能删除后再添加。key对应的value可以修改。
1)#include<map> --->map<type1, type2> mp;-->mp.insert(pair<type1, type2>(1, 20 ));//
常用函数:find()查找一个元素
--一个是基于hash表实现,一个是基于红黑树实现。
//Map是关联容器,以键值对的形式进行存储,方便进行查找。关键词起到索引的作用,值则表
//示与索引相关联的数据。以红黑树的结构实现,插入删除等操作都在O(logn)时间内完成
http://www.cnblogs.com/TianFang/archive/2006/12/30/607859.html
三、另外有其他容器hash_map,hash_set,hash_multiset,hash_multimap。
四、STL迭代器
Iterator(迭代器)模式又称Cursor(游标)模式,用于提供一
种方法顺序访问一个聚合对象中各个元素,
迭代器的作用:能够让迭代器与算法不干扰的相互发展,最后又能无间隙的粘合起来,
重载了*,++,==,!=,=运算符。用以操作复杂的数据结构,容器提供迭代器,
算法使用迭代器
常见的一些迭代器类型:iterator、const_iterator、reverse_iterator
和const_reverse_iterator
Insert Iterators(安插型迭代器)--
安插于容器最尾端
Front inserters(安插于容器的最前端)
Stream Iterators(流迭代器)
Reverse Iterators(逆向迭代器)
为何每次insert之后,以前保存的iterator不会失效?
答:iterator这里就相当于指向节点的指针,内存没有变,指向内存的指针怎么会失效呢
(当然被删除的那个元素本身已经失效了)。
3)为何map和set不能像vector一样有个reserve函数来预分配数据?
答:我以前也这么问,究其原理来说时,引起它的原因在于在map和set内部存储的已经不是元素本身了,
而是包含元素的节点。也就是说map内部使用的Alloc并不是map<Key,Data, Compare, Alloc>声明的时
候从参数中传入的Alloc。
五、STL中算法大致分为四类:
1)、非可变序列算法:指不直接修改其所操作的容器内容的算法。
2)、可变序列算法:指可以修改它们所操作的容器内容的算法。
3)、排序算法:包括对序列进行排序和合并的算法、搜索算法以及有序序列上的集合操作。
4)、数值算法:对容器内容进行数值计算。
六、适配器--queue、priority_queue、stack
适配器都是包装了vector、list、deque中某个顺序容器的包装器。注意:适配器没有提供迭代器,
也不能同时插入或删除多个元素。
-------
STL中的仿函数:仿函数主要用于STL中的算法中,虽然函数指针虽然也可以作为算法的参数,
但是函数指针不能满足STL对抽象性的要求,也不能满足软件积木的要求--函数指针无法和STL
其他组件搭配,产生更灵活变化。仿函数本质就是类重载了一个operator(),创建一个行为类
似函数的对象。