今天第一次接触到STL,觉得实在太厉害了,但是东西好多我怕我记不住,还是总结一下。
以后关于STL的东西都会陆续总结在这里,不过大多都是我从别的大佬那里看到的,我目前用到过的然后整理到一起。
目录
标准容器类 | 特点 |
顺序性容器 | |
vector | 从后面快速的插入与删除,直接访问任何元素 |
deque | 从前面或后面快速的插入与删除,直接访问任何元素 |
list | 双链表,从任何地方快速插入与删除 |
关联容器 | |
set | 快速查找,不允许重复值 |
multiset | 快速查找,允许重复值 |
map | 一对多映射,基于关键字快速查找,不允许重复值 |
multimap | 一对多映射,基于关键字快速查找,允许重复值 |
容器适配器 | |
stack | 后进先出 |
queue | 先进先出 |
priority_queue | 最高优先级元素总是第一个出列 |
c++中有两种类型的容器:顺序容器和关联容器,顺序容器主要有:vector、list、deque等。其中vector表示一段连续的内存地址,基于数组的实现,list表示非连续的内存,基于链表实现。deque与vector类似,但是对于首元素提供删除和插入的双向支持。关联容器主要有map和set。map是key-value形式的,set是单值。map和set只能存放唯一的key值,multimap和multiset可以存放多个相同的key值。
容器类自动申请和释放内存,我们无需new和delete操作。
一、顺序容器
容器的选择:vector和deque容器提供了对元素的快速随机访问,但付出的代价是在容器的任意位置插入或删除元素,比在容器尾部插入和删除的开销更大。list类型在任何位置都能快速插入和删除,但付出的代价是元素的碎甲访问开销较大。
1、vector
需要包含头文件#include<vector>
我对vector的理解其实就是可变长数组,就像java里的vector类,并且在这个容器里添加了很多实用的方法,还挺方便的,比单纯使用数组去自己写各种函数不知道方便多少倍,并且就像java中的泛型类一样,可以供不同数据类型使用,可以说是很棒了。
//1.定义和初始化
vector<int> vec1; //默认初始化,vec1为空
vector<int> vec2(vec1); //使用vec1初始化vec2
vector<int> vec3(vec1.begin(),vec1.end());//使用vec1初始化vec2
vector<int> vec4(10); //10个值为0的元素
vector<int> vec5(10,4); //10个值为4的元素
//2.常用操作方法
vec1.push_back(100); //尾部添加元素
int size = vec1.size(); //元素个数
bool isEmpty = vec1.empty(); //判断是否为空
cout<<vec1[0]<<endl; //取得第一个元素
vec1.insert(vec1.end(),5,3); //从vec1.back位置插入5个值为3的元素(即指向位置之前)
vec1.pop_back(); //删除末尾元素
vec1.erase(p) //删除迭代器p所指向的元素,返回一个迭代器,指向被删除元素后面的元素
vec1.erase(vec1.begin(),vec1.begin()+2);//删除vec1[0]-vec1[2]之间的元素,它指向被删除元素段内所有的元素
cout<<(vec1==vec2)?true:false; //判断是否相等==、!=、>=、<=...
vector<int>::iterator iter = vec1.begin(); //获取迭代器首地址
vector<int>::const_iterator c_iter = vec1.begin(); //获取const类型迭代器
vec1.clear(); //清空元素
vec1.resize(n); //调整vec1的长度大小,使其能容纳n个元素,如果n<vec1.size(),则删除多出来的元素;否则,添加采用值初始化的新元素
vec1.resize(n,t); //调整容器vec1的大小,使其能容纳n个元素,所有新添加的元素值为t
vec1.assign(b,e); //重新设置vec1的元素:将迭代器b和e标记的范围内所有的元素复制到vec1中,b和e必须不是指向c中元素的迭代器
vec1.assign(n,t); //将容器vec1重新设置为存储n个值为t的元素
//3.遍历
//下标法
int length = vec1.size();
for(int i=0;i<length;i++)
{
cout<<vec1[i];
}
cout<<endl<<endl;
//迭代器法
vector<int>::iterator iter = vec1.begin();
for(;iter != vec1.end();iter++)
{
cout<<*iter;
}
2、list
list是stl实现的双向链表,与向量vector想比,它允许快速的插入和删除,但是随机访问却是比较慢,需要添加头文件#include<list>
//1.定义和初始化
list<int> lst1; //创建空list
list<int> lst2(3); //创建含有三个元素的list
list<int> lst3(3,2); //创建含有三个元素为2的list
list<int> lst4(lst2); //使用lst2初始化lst4
list<int> lst5(lst2.begin(),lst2.end()); //同lst4
//2.常用操作方法
lst1.assign(lst2.begin(),lst2.end()); //分配值,3个值为0的元素
lst1.push_back(10); //末尾添加值
lst1.push_front(10); //前面添加值
lst1.pop_back(); //删除末尾值
lst1.begin(); //返回首值的迭代器
lst1.end(); //返回尾值的迭代器
lst1.clear(); //清空值
bool isEmpty1 = lst1.empty(); //判断为空
lst1.erase(lst1.begin(),lst1.end()); //删除元素
lst1.front(); //返回第一个元素的引用
lst1.back(); //返回最后一个元素的引用
lst1.insert(lst1.begin(),3,2); //从指定位置插入个3个值为2的元素
lst1.rbegin(); //返回第一个元素的前向指针
lst1.remove(2); //相同的元素全部删除
lst1.reverse(); //反转
lst1.size(); //含有元素个数
lst1.sort(); //排序
lst1.unique(); //删除相邻重复元素
//3.遍历
//迭代器法
for(list<int>::const_iterator iter = lst1.begin();iter != lst1.end();iter++)
{
cout<<*iter;
}
注意:
1.不要存储end操作返回的迭代器,添加或删除deque或vector容器内的元素都会导致存储的迭代器失效。
二、关联容器
1、set
set容器只是单纯的键的集合。当只想知道一个值是否存在时,使用set容器是最适合。需要包含头文件#include<set>
并且set中的键是唯一的,元素默认按升序排列。
//1.set容器的定义和使用
vector<int> ivec(20);
for ( int i=0; i<10; ++i )
{
ivec[2*i] = i;
ivec[2*i+1] = i;
}
// iset holds unique elements form ivec
set<int> iset( ivec.begin(), ivec.end() );
cout << ivec.size() << endl; // prints 20
cout << iset.size() << endl; // prints 10
//2.set容器的基本操作
set<int>s;
s.begin() //返回set容器的第一个元素
s.end() //返回set容器的最后一个元素
s.clear() //删除set容器中的所有的元素
s.empty() //判断set容器是否为空
s.insert() //插入一个元素
s.erase() //删除一个元素
s.size() //返回当前set容器中的元素个数
s.find() //返回一个指向被查找到元素的迭代器
s.count() //返回某个值元素的个数,其值只能是0或1
详见:https://blog.csdn.net/fengzhizi76506/article/details/54810086
2、map
自动建立Key - value的对应。key 和 value可以是任意你需要的类型。需要包含头文件#include<map>
详见:https://www.cnblogs.com/yutongzhu/p/5884269.html
三、容器适配器
1、stack
C++ Stack(堆栈) 是一个容器类的改编,为程序员提供了堆栈的全部功能,——也就是说实现了一个先进后出(FILO)的数据结构。需要包含头文件#include<stack>
empty() //堆栈为空则返回真
pop() //移除栈顶元素
push() //在栈顶增加元素
size() //返回栈中元素数目
top() //返回栈顶元素
2、queue
定义了先进先出的队列数据结构。需要包含头文件#include<queue>
back() //返回最后一个元素
empty() //如果队列空则返回真
front() //返回第一个元素
pop() //删除第一个元素
push() //在末尾加入一个元素
size() //返回队列中元素的个数
3、priority_queue
优先队列是队列的一种,所以需要包含头文件#include<queue>
优先队列虽然是个队列,但严格意义上来说已经不是了,它强调的是“优先”,本来队列是先进先出的选择,现在变成了谁的优先级高谁就先出。
priority_queue<Type,Container,Compare>
// Type 为数据类型
// Container 为保存数据的容器, 必须是用数组实现的容器,比如 vector, deque 但不能用list。STL里面默认用的是 vector
// Compare为元素比较方式。比较方式默认用 operator< , 所以如果你把后面俩个参数缺省的话,优先队列就是大顶堆,队头元素最大。
//所以如果要让小的数据先出队列的话,STL里面定义了一个仿函数 greater<>,对于基本类型可以用这个仿函数声明小顶堆。
priority_queue<int, vector<int>, greater<int> > q;
q.empty(); //如果优先队列为空,则返回真
q.pop(); //删除第一个元素
q.push(x) // 加入一个元素 x
q.size() //返回优先队列中拥有的元素的个数
q.top() //返回优先队列中有最高优先级的元素
但是在使用时必须注意:priority_queue放置元素时,不会判断元素是否重复。(因为在模板的第二个参数时顺序容器,不能保证元素的唯一性)此外可以替代默认的Compare函数。
1.lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
lower_bound(a,a+n,x)-a 即返回a数组的第一个大于或等于x元素的位置
2.upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
upper_bound(a,a+n,x)-a 即返回a数组的第一个大于x元素的位置