STL容器用法详解

参考: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<int> mydeque(5,10);//5个10
vector<int> myvector(3,20);//3个20
queue<int>s1;
queue<int>s2(mydeque);//复制一份mydeque
queue<int,vector<int> >s3;//使用vector初始化stack
queue<int,vector<int> >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(栈)栈是一种数据结构,它按照后进先出的原则存储数据,先进入的数据被压入栈底,最后的数据在栈顶,需要读数据的时候从栈顶开始弹出数据。(用法和队列相似
stack<int>q;
构造类函数:
deque<int> mydeque(5,10);//5个10
vector<int> myvector(3,20);//3个20
stack<int>s1;
stack<int>s2(mydeque);//复制一份mydeque
stack<int,vector<int> >s3;//使用vector初始化stack
stack<int,vector<int> >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 a<b;//最大值优先
    }
};
//定义结构,使用运算符重载,自定义优先级2
struct number1
{
    int x;
    bool operator < (const number1 &a) const
    {
        return x>a.x;//最小值优先
    }
};
struct number2
{
    int x;
    bool operator < (const number2 &a) const
    {
        return x<a.x;//最大值优先
    }
};
priority_queue<int>que;//采用默认优先级构造队列
priority_queue<number1>que;//最小值优先
priority_queue<number1>que;//最大值优先

priority_queue<int,vector<int>,cmp1>que1;//最小值优先
priority_queue<int,vector<int>,cmp2>que2;//最大值优先

priority_queue<int,vector<int>,greater<int> >que3;//注意“>>”会被认为错误,这是右移运算符,所以这里用空格号隔开
priority_queue<int,vector<int>,less<int> >que4;//最大值优先


Ⅳdeque(双端队列):是一种具有队列和栈的性质的数据结构。双端队列中的元素可以从两端弹出,其限定插入和删除操作在表的两端进行。

构造类函数:
deque<char> s1;
deque<char> s2(5,'6');
deque<char> s3(s2.begin(),s2.end());
deque<char> s4(s2);
A=B//可以通过=把B的内容复制到A里
迭代器函数:
deque<char>a;
deque<char>::iterator it;//本质就是指针STL都是通过指针进行迭代。
for(it=a.begin();it!=a.end();it++)//顺序迭代
deque<char>::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<char> s1;
vector<char> s2(5,'6');
vector<char> s3(s2.begin(),s2.end());
vector<char> s4(s2);
A=B//可以通过=把B的内容复制到A里
迭代器函数:
vector<char>a;
vector<char>::iterator it;//本质就是指针STL都是通过指针进行迭代。
for(it=a.begin();it!=a.end();it++)//顺序迭代
vector<char>::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

构造类函数:
list<char> s1;
list<char> s2(5,'6');
list<char> s3(s2.begin(),s2.end());
list<char> s4(s2);
A=B//可以通过=把B的内容复制到A里
迭代器函数:
list<char>a;
list<char>::iterator it;//本质就是指针STL都是通过指针进行迭代。
for(it=a.begin();it!=a.end();it++)//顺序迭代
list<char>::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_to<int>mypred);好复杂不会用— —大哭,以后再学吧
L1.merge(L2):将两个list合并,按插入排序的方式合并
a.sort():对list中元素排序,可在括号内加入模版类对象控制排序方式,greater<int>或less<int>
a.reverse():将list中元素倒置

Ⅶ set

set是用红黑树的平衡二叉索引树的数据结构来实现的,插入时,它会自动调节二叉树排列,把元素放到适合的位置,确保每个子树根节点的键值大于左子树所有的值、小于右子树所有的值,插入重复数据时会忽略。set迭代器采用中序遍历,检索效率高于vector、deque、list,并且会将元素按照升序的序列遍历。set容器中的数值,一经更改,set会根据新值旋转二叉树,以保证平衡,构建set就是为了快速检索(python中的set一旦建立就是一个常量,不能改的)。


构造类函数:
set<char> s1;
char a[]={'a','b','c','d','e'};
set<char> s2(a,.a+5);
set<char> s3(s2);
A=B//可以通过=把B的内容复制到A里
迭代器函数:
set<char>a;
set<char>::iterator it;//本质就是指针STL都是通过指针进行迭代。
for(it=a.begin();it!=a.end();it++)//顺序迭代
set<char>::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都能用。

构造类函数:
map<int,string> mapStudent;
第一空填入键值,map按键值排序,键值也可以是结构体,不过结构体内部要写一个排序,同优先队列。
其他用法和set一样
A=B//可以通过=把B的内容复制到A里
迭代器函数:
map<int,string>a;
map<int,string>::iterator it;//本质就是指针STL都是通过指针进行迭代。
for(it=a.begin();it!=a.end();it++)//顺序迭代
map<int,string>::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




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就能计算出地址
由于分过段的后链表的长度也不是很长,所以遍历对于
整体性能的影响就微乎其微了。


  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值