参考:http://www.cnblogs.com/duoduo369/archive/2012/04/12/2439118.html
参考:http://blog.csdn.net/pcsuite/article/details/6183504
1.STL容器分类:
STL的容器可以分为以下几个大类:
一 顺序容器,vector, list, deque, string,stack( 适配器类), queue( 适配器类), priority_queue( 适配器类)
二 关联容器,set, multiset, map, multimap, bitset,hash_set, hash_map, hash_multiset, hash_multimap
关联容器(Associative Container)与顺序容器(Sequential Container)的本质区别在于:
关联容器是通过键(key)存储和读取元素的,而顺序容器则通过元素在容器中的位置顺序存储和访问元素。
Ⅰ queue(队列):队列是一种特殊的线性表,是一种先进先出(FIFO)的数据结构。它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称为空队列。
构造类函数:
deque mydeque(5,10);//5个10
vector myvector(3,20);//3个20
queues1;
queues2(mydeque);//复制一份mydeque
queue >s3;//使用vector初始化stack
queue >s4(myvector);//复制一份myvector
容量类函数:
q.empty()判断队列q是否为空,当队列q空时,返回true;否则为false。
q.size()访问队列q中的元素个数。
存取类函数:
q.front()会返回队列q内的第一个元素(也就是第一个被置入的元素)。
q.back()会返回队列q中最后一个元素(也就是最后被插入的元素)。
操作类函数:
q.push(a)会将一个元素a置入队列q中。
q.pop()会从队列q中移除第一个元素。
Ⅱstack(栈):栈是一种数据结构,它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据。(用法和队列相似)
stackq;
构造类函数:
deque mydeque(5,10);//5个10
vector myvector(3,20);//3个20
stacks1;
stacks2(mydeque);//复制一份mydeque
stack >s3;//使用vector初始化stack
stack >s4(myvector);//复制一份myvector
容量类函数:
q.empty()判断队列q是否为空,当队列q空时,返回true;否则为false。
q.size()访问队列q中的元素个数。
存取类函数:
q.top() 返回栈顶元素。
操作类函数:
q.push(a)会将一个元素a置入队列q中。
q.pop()会从队列q中移除第一个元素。
Ⅲpriority_queue优先队列,用法和队列一样,多了个排序功能。
priority_queue<int> qi;
括号内放各种数据类型或容器,默认从大到小排列,大的在队首先出来。
priority_queue<int, vector<int>, greater<int> >qi2;
第一个参数为数据类型。
第二个参数为容器类型。
第三个参数为比较函数。
struct cmp1
{
bool operator ()(int &a,int &b)
{
return a>b;//最小值优先
}
};
struct cmp2
{
bool operator ()(int &a,int &b)
{
return aa.x;//最小值优先
}
};
struct number2
{
int x;
bool operator < (const number2 &a) const
{
return xque;//采用默认优先级构造队列
priority_queueque;//最小值优先
priority_queueque;//最大值优先
priority_queue,cmp1>que1;//最小值优先
priority_queue,cmp2>que2;//最大值优先
priority_queue,greater >que3;//注意“>>”会被认为错误,这是右移运算符,所以这里用空格号隔开
priority_queue,less >que4;//最大值优先
Ⅳdeque(双端队列):是一种具有队列和栈的性质的数据结构。双端队列中的元素可以从两端弹出,其限定插入和删除操作在表的两端进行。
构造类函数:
deque s1;
deque s2(5,'6');
deque s3(s2.begin(),s2.end());
deque s4(s2);
A=B//可以通过=把B的内容复制到A里
迭代器函数:
dequea;
deque::iterator it;//本质就是指针STL都是通过指针进行迭代。
for(it=a.begin();it!=a.end();it++)//顺序迭代
deque::reverse_iterator it;
for(it=a.rbegin();it!=a.rend();it++)//逆序迭代
容量类函数:
a.size()//返回容器实际元素个数
a.max_size()//返回容器最大能容纳元素的个数
a.empty()//判断容器是否为空,空返回true,否则返回false。
a.resize(6,50)//将容器a大小变为6,不足用50扩充,第二空可以省略,默认用0扩充
存取类函数:
a[6]:可以用[]进行存取,是一种运算符重载函数,和数组差不多用。
a.at(6):和[]一样进行存取。进行越界检查
a.front()//返回第一个元素
a.back()//返回最后一个元素
操作类
a1.assign(6,10)//给容器a赋值6个10.
a2.assign(a1.begin(),a1,end())//复制一个a1
a.push_back(6)//在末端插入一个6
a.push_front(6)//在开头插入一个6
a.pop_back()//删除末端一个元素
a.pop_front()//删除开头一个元素
a.insert(it,6);//在it位置插入一个6 //it是容器a中的某个位置的指针,
a.insert(it,6,8);//在it位置插入8个6
a.insert(it,a1.begin(),a1.end());//在it位置插入a1
a.erase(it)//删除该位置会导致其他元素的移动,很耗时不如list来的快。
a.erase(it,it+6)或者a.erase(it,a.end())//删除某一区间内的元素
a.clear()清空容器a
a1.swap(a2)//交换a1和a2
Ⅴ vector
构造类函数:
vector s1;
vector s2(5,'6');
vector s3(s2.begin(),s2.end());
vector s4(s2);
A=B//可以通过=把B的内容复制到A里
迭代器函数:
vectora;
vector::iterator it;//本质就是指针STL都是通过指针进行迭代。
for(it=a.begin();it!=a.end();it++)//顺序迭代
vector::reverse_iterator it;
for(it=a.rbegin();it!=a.rend();it++)//逆序迭代
容量类函数:
a.size()//返回容器实际元素个数
a.max_size()//返回容器最大能容纳元素的个数
a.empty()//判断容器是否为空,空返回true,否则返回false。
a.resize(6,50)//将容器a大小变为6,不足用50扩充,第二空可以省略,默认用0扩充
a.capacity()//容器的储存空间大小
存取类函数:
a[6]:可以用[]进行存取,是一种运算符重载函数,和数组差不多用。
a.at(6):和[]一样进行存取。进行越界检查
a.front()//返回第一个元素
a.back()//返回最后一个元素
操作类
a1.assign(6,10)//给容器a赋值6个10.
a2.assign(a1.begin(),a1,end())//复制一个a1
a.push_back(6)//在末端插入一个6
a.pop_back()//删除末端一个元素
a.insert(it,6);//在it位置插入一个6 //it是容器a中的某个位置的指针,
a.insert(it,6,8);//在it位置插入8个6
a.insert(it,a1.begin(),a1.end());//在it位置插入a1
a.erase(it)//删除该位置会导致其他元素的移动,很耗时不如list来的快。
a.erase(it,it+6)或者a.erase(it,a.end())//删除某一区间内的元素
a.clear()清空容器a
a1.swap(a2)//交换a1和a2
Ⅵ list
![](http://img.e-com-net.com/image/info8/71c6e49c97fb41758cc9cfb71c9a818d.jpg)
构造类函数:
list s1;
list s2(5,'6');
list s3(s2.begin(),s2.end());
list s4(s2);
A=B//可以通过=把B的内容复制到A里
迭代器函数:
lista;
list::iterator it;//本质就是指针STL都是通过指针进行迭代。
for(it=a.begin();it!=a.end();it++)//顺序迭代
list::reverse_iterator it;
for(it=a.rbegin();it!=a.rend();it++)//逆序迭代
容量类函数:
a.size()//返回容器实际元素个数
a.max_size()//返回容器最大能容纳元素的个数
a.empty()//判断容器是否为空,空返回true,否则返回false。
a.resize(6,50)//将容器a大小变为6,不足用50扩充,第二空可以省略,默认用0扩充
存取类函数:
a.front()//返回第一个元素
a.back()//返回最后一个元素
操作类
a1.assign(6,10)//给容器a赋值6个10.
a2.assign(a1.begin(),a1,end())//复制一个a1
a.push_back(6)//在末端插入一个6
a.push_front(6)//在开头插入一个6
a.pop_back()//删除末端一个元素
a.pop_front()//删除开头一个元素
a.insert(it,6);//在it位置插入一个6 //it是容器a中的某个位置的指针,
a.insert(it,6,8);//在it位置插入8个6
a.insert(it,a1.begin(),a1.end());//在it位置插入a1
a.erase(it)//删除该位置会导致其他元素的移动,很耗时不如list来的快。
a.erase(it,it+6)或者a.erase(it,a.end())//删除某一区间内的元素
a.clear()清空容器a
a1.swap(a2)//交换a1和a2
L1.splice(it,L2)//将容器L2移动到L1中的it位置,并将L2中的元素删除。
L1.splice(it1,L2,it2)//将容器L2中it2指向的元素移动到L1中的it1指向的位置
a.remove(value)//将容器a中值为value的元素删除
remove_if:好复杂不会用— —,
a.unique():删除list中相邻重复的元素
a.unique(not_equal_tomypred);好复杂不会用— —,以后再学吧
L1.merge(L2):将两个list合并,按插入排序的方式合并
a.sort():对list中元素排序,可在括号内加入模版类对象控制排序方式,greater或less
a.reverse():将list中元素倒置
Ⅶ set
set是用红黑树的平衡二叉索引树的数据结构来实现的,插入时,它会自动调节二叉树排列,把元素放到适合的位置,确保每个子树根节点的键值大于左子树所有的值、小于右子树所有的值,插入重复数据时会忽略。set迭代器采用中序遍历,检索效率高于vector、deque、list,并且会将元素按照升序的序列遍历。set容器中的数值,一经更改,set会根据新值旋转二叉树,以保证平衡,构建set就是为了快速检索(python中的set一旦建立就是一个常量,不能改的)。
![STL容器用法详解_第1张图片](http://img.e-com-net.com/image/info8/37580a5ea4f140cca61a835703866bed.jpg)
构造类函数:
set s1;
char a[]={'a','b','c','d','e'};
set s2(a,.a+5);
set s3(s2);
A=B//可以通过=把B的内容复制到A里
迭代器函数:
seta;
set::iterator it;//本质就是指针STL都是通过指针进行迭代。
for(it=a.begin();it!=a.end();it++)//顺序迭代
set::reverse_iterator it;
for(it=a.rbegin();it!=a.rend();it++)//逆序迭代
容量类函数:
a.size()//返回容器实际元素个数
a.max_size()//返回容器最大能容纳元素的个数
a.empty()//判断容器是否为空,空返回true,否则返回false。
操作类
a.insert(6);//插入一个6
a.insert(it,6);//在it位置开始在合适位置插入一个6,
a.insert(a1.begin(),a1.end());//位置插入a1
a.erase(6)//删除a中的元素6
a.erase(it,it+6)或者a.erase(it,a.end())//删除某一区间内的元素
a.clear()清空容器a
a1.swap(a2)//交换a1和a2
a.find(value),//查找值为value的元素,返回他的指针,没有就返回end();
a.count()//查找值为value的元素,存在返回1,不存在返回0;
a.lower_bound()//二分查找,大于等于该元素的第一个,返回指针
a.upper_bound()//二分查找,大于该元素的第一个,返回指针
a.equal_range()//返回一对迭代器,即a中该元素的边界,例如1,2,4,5,输入3,返回2,4;
Ⅷ map
map也是使用红黑树,他是一个键值对(key:value映射),便利时依然默认按照key程序的方式遍历,同set。
map和set最大的区别在于,map可以像数组一样使用,因为map有键值和映照数据两部分组成,set能用的map都能用。
![STL容器用法详解_第2张图片](http://img.e-com-net.com/image/info8/4109e0a4001746c8925139423461d6a3.jpg)
构造类函数:
map mapStudent;
第一空填入键值,map按键值排序,键值也可以是结构体,不过结构体内部要写一个排序,同优先队列。
其他用法和set一样
A=B//可以通过=把B的内容复制到A里
迭代器函数:
mapa;
map::iterator it;//本质就是指针STL都是通过指针进行迭代。
for(it=a.begin();it!=a.end();it++)//顺序迭代
map::reverse_iterator it;
for(it=a.rbegin();it!=a.rend();it++)//逆序迭代
容量类函数:
a.size()//返回容器实际元素个数
a.max_size()//返回容器最大能容纳元素的个数
a.empty()//判断容器是否为空,空返回true,否则返回false。
操作类:
a[6]//可以直接像数组一样使用[],括号内填入已有的键值,返回的就是映照数据。
a[6]="swear"//同样的括号也可以用来赋值,如果存在会覆盖掉已有的值
三种插入操作:
a.insert(pair<int,string>(3,"student_three"))//插入操作不会覆盖已有的内容。
a.insert(make_pair(1,'@'))
a.insert(map<int, string>::value_type (1, "student_one"));
其他函数(使用方式和set一样)
a.clear()清空容器a
a1.swap(a2)//交换a1和a2
a.find(value),//查找键值为value的元素,返回pair类型的迭代器,没有就返回end();
a.count(value)//查找键值为value的元素,存在返回1,不存在返回0;
a.lower_bound(value)//二分查找,大于等于该元素的第一个,返回pair类型的迭代器
a.upper_bound(value)//二分查找,大于该元素的第一个,返回pair类型的迭代器
a.equal_range(value)//返回一对迭代器,即a中该元素的边界,例如1,2,4,5,输入3,返回2,4;
Ⅸ bitset
![STL容器用法详解_第3张图片](http://img.e-com-net.com/image/info8/7bfd8263d5e54ea89e0918f153691c95.jpg)
![STL容器用法详解_第4张图片](http://img.e-com-net.com/image/info8/c70b349032424a6ab7714b9e3350981b.jpg)
vector,deque,list对比
vector - 会自动增长的数组
vector又称为向量数组,他是为了解决程序中定义的数组是
不能动态改变大小这个缺点而出现的。
一般程序实现是在类创建的时候同时创建一个定长数组,
随着数据不断被写入,一旦数组被填满,则重新开辟一块更大的内存区,
把原有的数据复制到新的内存区,抛弃原有的内存,如此反复。
由于程序自动管理数组的增长,对于我们程序员来说确实轻松了不少,
只管把数据往里面插就行了,当然把物理内存和虚拟内存插爆掉了
就是操作系统来找你麻烦了:-)
vector由于数组的增长只能向前,所以也只提供了后端插入和后端删除,
也就是push_back和pop_back。当然在前端和中间要操作数据也是可以的,
用insert和erase,但是前端和中间对数据进行操作必然会引起数据块的移动,
这对性能影响是非常大的。
对于所有数组来说,最大的优势就是随机访问的能力。
在vector中,提供了at和[]运算符这两个方法来进行随机访问。
由于每个数据大小相同,并且无间隔地排列在内存中,
所以要对某一个数据操作,只需要用一个表达式就能直接计算出地址:
address = base + index * datasize
同样,对vector进行内存开辟,初始化,清除都是不需要花大力气的,
从头到尾都只有一块内存。
list - 擅长插入删除的链表
有黑必有白,世界万物都是成对出现的。
链表对于数组来说就是相反的存在。
数组本身是没有动态增长能力的(程序中也必须重新开辟内存来实现),
而链表强悍的就是动态增长和删除的能力。
但对于数组强悍的随机访问能力来说的话,链表却很弱。
list是一个双向链表的实现。
为了提供双向遍历的能力,list要比一般的数据单元多出两个指向前后的指针。
这也是没办法的,毕竟现在的PC内存结构就是一个大数组,
链表要在不同的环境中实现自己的功能就需要花更多空间。
list提供了push_back,push_front,pop_back,pop_front四个方法
来方便操作list的两端数据的增加和删除,不过少了vector的at和[]运算符的
随机访问数据的方法。并不是不能实现,而是list的设计者
并不想让list去做那些事情,因为他们会做得非常差劲。
对于list来说,清除容器内所有的元素是一件苦力活,
因为所有数据单元的内存都不连续,list只有一个一个遍历来删除。
deque - 拥有vector和list两者优点的双端队列
黑与白,处于这两个极端之间的就是令人愉悦的彩色了。
deque作为vector和list的结合体,确实有着不凡的实力。
STL的deque的实现没有怎么去看过,不过根据我自己的猜测,
应该是把数组分段化,在分段的数组上添加指针来把所有段连在一起,
最终成为一个大的数组。
deque和list一样,提供了push_back,push_front,
pop_back,pop_front四个方法。可以想象,如果要对deque的两端进行操作,
也就是要对第一段和最后一段的定长数组进行重新分配内存区,
由于分过段的数组很小,重新分配的开销也就不会很大。
deque也和vector一样,提供了at和[]运算符的方法。
要计算出某个数据的地址的话,虽然要比vector麻烦一点,
但效率要比list高多了。
首先和list一样进行遍历,每次遍历的时候累积每段数组的大小,
当遍历到某个段,而且baseN <= index < baseN + baseN_length的时候,
通过address = baseN + baseN_index就能计算出地址
由于分过段的后链表的长度也不是很长,所以遍历对于
整体性能的影响就微乎其微了。