【C++】STL容器


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

····

C++STL容器总结 特别详细!!!
C/C++STL常用容器用法总结
C++容器详解

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值