文章目录
STL 对定义的通用容器分三类:顺序性容器、关联式容器和容器适配器。
可以用下标访问的容器有(既可以插入也可以赋值):vector、deque、map
顺序性容器
特别要注意一下,vector和deque如果没有预先指定大小,是不能用下标法插入元素的!
一、vector (向量)
这道约瑟夫环问题,是本蒟蒻第一次认识到vector。
#include<iostream>
#include<vector>//所需的头文件
using namespace std;
int main()
{
int n,m;
vector<int>a;//定义vector数组a
while(cin>>n>>m)
{
if(!n&&!m)
break;
for(int i=1; i<=n; i++)
{
a.push_back(i);//在vector末尾插入元素
}
int j=0;
while(a.size()>1)//当数组内有数时进行循环
{
j=(j+m-1)%a.size();//vector数组下标从0开始
//cout<<a[j]<<' ';
a.erase(a.begin()+j);//删除下标为j的元素
}
cout<<a[0]<<endl;
a.clear();//清空数组,不清空会对后续测试用例造成影响
}
return 0;
}
相关链接:
c++ vector(向量)使用方法详解
C语言的数组和STL的vector的互相转换
vector对象的基本操作
v.empty() //如果v为空,则返回true,否则返回false。
v.size() //返回v中元素的个数。
v.push_back(t) //在v的末尾增加一个值为t的元素。
v[n] //返回v中位置为n的元素。
v1=v2 //把v1的元素替换成v2中元素的副本。
v1==v2 //如果v1与v2相等,则返回true。
!=, <, <=, >, >= //保持这些操作符惯有的含义。
以下内容转载自该博客:【C++】STL常用容器总结之三:向量vector
vector元素的常用操作
这里我们以vector< int > c;为例进行说明。
1、容器的大小操作
c.max_size():返回向量类型的最大容量(2^30-1=0x3FFFFFFF)
c.capacity():返回向量当前开辟的空间大小(<= max_size,与向量的动态内存分配策略相关)。
c.size():返回向量中现有元素的个数(<=capacity)。
c.resize(n):调整向量的长度使其能容纳n个元素。
c.resize(n,x):把向量的大小改为n,所有新元素的初值赋为x。
c.empty():如果向量为空,返回真。
2、元素的赋值操作
c.assign(first,last):将迭代器first,last所指定范围内的元素复制到c 中。
c.assign(num,val):用val的num份副本重新设置c。
3、元素的访问操作
c.at(n):等价于下标运算符[],返回向量中位置n的元素,因其有越界检查,故比[ ]索引访问安全。
c.front():返回向量中第一个元素的引用。
c.back():返回向量中最后一个元素的引用。
c.begin():返回向量中第一个元素的迭代器。
c.end():返回向量中最后一个元素的下一个位置的迭代器,仅作结束游标,不可解引用。
c.rbegin():返回一个反向迭代器,该迭代器指向容器的最后一个元素。
c.rend():返回一个反向迭代器,该迭代器指向容器第一个元素前面的位置。
4、元素的删除操作
c.pop_back():删除向量最后一个元素。
c.clear():删除向量中所有元素。
c.erase(iter):删除迭代器iter所指向的元素,返回一个迭代器指向被删除元素后面的元素。
c.erase(start, end):删除迭代器start、end所指定范围内的元素,返回一个迭代器指向被删除元素段后面的元素。
5、元素的插入操作
c.push_back(x):把x插入到向量的尾部。
c.insert(iter, x):在迭代器iter指向的元素之前插入值为x的新元素,返回指向新插入元素的迭代器。
c.insert(iter,n,x):在迭代器iter指向的元素之前插入n个值为x的新元素,返回void。
c.insert(iter,start,end):把迭代器start和end所指定的范围内的所有元素插入到迭代器iter所指向的元素之前,返回void。
a.insert(a.begin()+i,c);///将值为c的新元素插入到a[i]
6、元素的交换操作
c.reverse():反转元素顺序。
c.swap(c2):交换2个向量的内容,c和c2 的类型必须相同。
(注意这里利用c.clear()对vector清空后并没有释放内存,此时清空后后续向vector中添加元素会出现不是重新从0下标开始的问题)
清空并释放内存的操作代码如下:
vector<int>c;//定义vector
vector<int>().swap(c);//清空vector中的元素并释放vector的内存
/*结构体vector向量:*/
struct node
{
····
····
}
vector<node>c;
vector<node>().swap(c);
具体详情见: 简单的程序诠释C++ STL算法系列之十五:swap
注意:并不是所有的STL容器的clear成员函数的行为都和vector一样。事实上,其他容器的clear成员函数都会释放其内存。比如另一个和vector类似的顺序容器deque。
二、deque
···
三、list
先放个链接,以后再看:
【C++】STL常用容器总结之四:链表list
【STL】list基础
以下问答摘自百度:
问:
C++STL的list插入时,如何对链表中间的任意位置插入元素:
不要说这样:
a.insert(++a.begin(),5,100); 这只能在链表中第一个元素后插入第二个元素,第三个就没办法了。
还有读表中任意一个元素怎么读(一次性的),不要说
list::iterator j;
for(j=a.begin();j!=a.end();j++)
cout<<*j<<endl;这个一输出一大堆
答:
没有直接根据第几个元素来插入的函数,不过可以这样来插入第n个元素
list< int >::iterator j = a.begin();
for(i = 0; i < n && j!= a.end(); ++i)
++j;
a.insert(j,5,100);
读任意一个元素也可以用同样方法
追问:
为什么这里用!=而不是< ?
还有++i和++i在这里没区别吧?
追答:
因为j是list::iterator类型,本质上是一个指针,对于list来说相邻两个结点的地址大小是不可预计的,而只能判断是否相等,因此list::iterator没有定义operator <,如果是vector则可以用<,因为vector是顺序存储。
在这里i++个++i效果是一样的,但是++i比i++性能更好,i++先使用i后i加加,需要另外开辟内存来存储i的值,而++i只需把i本身加1然后返回即可。
题目:
模拟线性表:
INIT 初始化线性表
PRINT 输出一行:从头到尾输出线性表每一个元素,每个元素尾随一个空格
ADD x value 把value插入到线性表的第x个位置,如果x超过线性表的元素个数,则把value作为线性表最后一个元素。
DELETE x 删除线性表的第x个元素,如果x超过线性表的元素个数,则不做任何处理。
LENGTH 输出当前线性表的元素个数
线性表的首元素位置定义为1,它后面的元素的位置定义为2,以此类推。
线性表的元素都是整数,且绝对值小于10000。
Sample Input
11
INIT
ADD 1 5
ADD 1 4
ADD 1 3
LENGTH
ADD 1 2
ADD 1 1
PRINT
DELETE 5
LENGTH
PRINT
Sample Output
3
1 2 3 4 5
4
1 2 3 4
Code
#include<iostream>
#include<list>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
int n,k=0,c,d;
list<int>b; //定义
list<int>::iterator iter; //迭代器
char a[8]={};
cin>>n;
for(int i=1;i<=n;i++){
cin>>a;
if(a[0]=='I')
b.clear(); //清空链表
else if(a[0]=='A'){
cin>>c>>d;
if(c>b.size())
b.push_back(d); //将元素d加入到链表末尾
else if(c<1)continue;
else{
iter=b.begin();
for(int j=1;j<c;++j)
++iter;
b.insert(iter,d); //将元素d插入到链表的第c个位置
}
}
else if(a[0]=='L')
cout<<b.size()<<endl; //返回链表元素个数
else if(a[0]=='P'){
for(iter=b.begin();iter!=b.end();iter++)
cout<<*iter<<' '; //按顺序输出链表中的元素
cout<<endl;
}
else if(a[0]=='D'){
cin>>c;
if(c>b.size()||c<1)continue;
iter=b.begin();
for(int j=1;j<c;++j)
++iter;
b.erase(iter); //删除链表的第c个元素
}
}
return 0;
}
关联式容器
内部实现是采用二叉树结构(红黑树的结构)原理实现的。
顺序性容器可以在容器初始化的时候制定大小,关联式容器不行。
关联容器的迭代器不支持it+n操作,仅支持it++操作。
四、set / multiset / unordered_set (集合)
set:存储的是一组无重复的元素,自动排序。
multiset:允许存储有重复的元素,自动排序。
unordered_set:存储无重复的元素,是无序的,其实现基于哈希表。
①不可用下标访问set容器,即不支持随机访问。
②无法直接修改元素。
1.set的定义:
set< int >s; //默认升序
set< int > s(s2); // 创建容器s2的副本s
set< int > s(b, e); // 创建s,其元素是迭代器b和e标示的范围内元素的副本
set< int ,op(比较结构体) >s; //op为排序规则,降序为greater< int >,也可自定义比较结构体,如下
struct mycmp{ //定义比较结构体
bool operator()(const int &a,const int &b){ //重载“()”操作符
if(a!=b)return a>b;
else return false;//a、b相等时不插入
}
};
int main(){
set<int,mycmp>s={5,6,3,5,0,4,9,3,1};
for(auto i:s)cout<<i<<' ';
//输出:9 6 5 4 3 1 0
}
2.set的操作:
s.size();
元素的数目
s.max_size();
可容纳的最大元素的数量
s.empty();
判断容器是否为空
s.count(elem);
set中elem个数只能是1或0,所以可用于判断set中某一键值是否存在。multiset中可以大于一。
s.insert(elem);
返回值是pair<set< int >::iterator, bool>,bool标志着插入是否成功,而iterator代表插入的位置,若elem已在set中,则iterator表示elem在set中的位置。若elem不存在,则插入。
s.insert(begin,end);
插入begin到end区间内的元素,返回值void
s.erase(elem);
删除elem元素
s.erase(iter);
删除迭代器iter指向的元素
s.erase(begin,end);
删除begin到end区间内的元素(左闭右开)
s.find(elem);
如果查找到elem,则返回该元素的迭代器位置;否则,返回集合最后一个元素后面的一个位置,即end()。
s.clear()
清除所有元素
s.lower_bound(x)
返回指向第一个大于等于x元素的迭代器
s.upper_bound(y)
返回指向第一个大于y元素的迭代器(这里的大于是指在一段有序序列中,右大左小)
set<int,greater<int> >s={1,3,5,7,9};
auto it1 = s.lower_bound(3);
auto it2 = s.upper_bound(7);
cout << *it1 << endl;//输出为3
cout << *it2 << endl;//输出为5
3.set的遍历
set<int>s;
/*顺序遍历*/
for(auto i:s)
cout<<i<<endl;
for(set<int>::iterator it=s.begin();it!=s.end();it++)
cout<<*it<<endl;
for(auto it=s.begin();it!=s.end();it++)
cout<<*it<<endl;
/*反序遍历*/
for(set<int>::reverse_iterator it=s.rbegin();it!=s.rend();it++)
cout<<*it<<endl;
for(auto it=s.rbegin();it!=s.rend();it++)
cout<<*it<<endl;
set集合求交集、并集、差集
并集 set_union
交集 set_intersection
差集 set_difference
vector<int>c,d,e,f;
set<int>a={5,4,3,2,1},b={7,6,5,4};
//传入的a,b不一定是set,但一定要有序(从小到大)
set_difference(a.begin(),a.end(),b.begin(),b.end(),inserter(c,c.begin()));//a-b
set_difference(b.begin(),b.end(),a.begin(),a.end(),inserter(d,d.begin()));//b-a
set_union(a.begin(),a.end(),b.begin(),b.end(),inserter(e,e.begin()));//a∪b
set_intersection(a.begin(),a.end(),b.begin(),b.end(),inserter(f,f.begin()));//a∩b
for(auto i:c)cout<<i<<' ';puts("");//1 2 3
for(auto i:d)cout<<i<<' ';puts("");//6 7
for(auto i:e)cout<<i<<' ';puts("");//1 2 3 4 5 6 7
for(auto i:f)cout<<i<<' ';puts("");//4 5
五、map / multimap / unordered_map (映射)
先放个链接:【C++】STL常用容器总结之八:映射map
···
容器适配器
六、stack
···
七、queue
···
八、priority_queue
····