C++STL容器超详介绍

C++stl容器超详介绍

声明

这篇文章属于原创,是从本人的洛谷专栏中搬过来的。转载请经过本人同意,且转载后请注明出处,否则将举报。

引入

线性数据结构 称为container

vector

begin是第一个数据的地址,而end是最后一个数据的下一个地址。

特殊的

for(auto i:a){
    cout<<i<<' ';
}
//for range语法

for(auto it=a.begin();it!=a.end();it++){
    auto i=*it;
    cout<<i<<' ';
}

的效果是相同的。

为循环变量值修改会修改原vector的值吗?

在这段代码中,加入i=4,是不会修改原vector a的值的,只会修改i的值。

for(auto i:a){
   cout<<i<<' ';
   i=4;
}

因为其等价于

for(auto it=a.begin();it!=a.end();it++){
    auto i=*it;
    cout<<i<<' ';
    i=4;
}

但是,当在代码中加入取地址符号&时,会直接影响vector a中的值。

for(auto &i:a){
   cout<<i<<' ';
   i=4;
}

因为其等价于

for(auto it=a.begin();it!=a.end();it++){
    auto &i=*it;//取了*it的地址,修改i时就会直接修改*it
    cout<<i<<' ';
    i=4;
}

建立vector

有三种

std::vector<int>a;//建立vector a
std::vector<int>a(n);//建立长度为n的vector a
std::vector<int>a(n,i);//建立长度为n,初始值都为i的vector a

嵌套vector

vector中的数据类型也可以嵌套vector
例如,构造一个二维\(n*m\)的vector嵌套,可以用如下代码。

vector<vector<int>>a(n,vector<int>(m));
//等价于 int[n][m];
//定义一个类型为vector的vector,长度为n,初始值都为初始值为m的vector<int>

注意

二维数组是开了一个n*m的内存,而二维vector是开了n个m的内存,n个m在内存中可能不连续。

vector的优点

  1. vector可以成为局部变量(数据),而数组不可以。
  2. vector在不规定初始值时默认是0,而数组如果作为局部变量时初始值时随机的,需要耗费 O(\(n^{数组维度}\)) 的时间复杂度来归零。

priority_queue优先队列

建立

std::priority_queue<int>q;

相当于自动排序

:队列没有指针,不能使用for range遍历队列

大小根堆

priority_queue默认大根堆(从大到小排序
如果想要改成小根堆可以在建立时加入比较器

std::priority_queue<int,vector<int>,greater<int>>q;
//大根堆的仿函数比较器是less,但是默认是大根堆,所以不常用。
//std::priority_queue<int,vector<int>,less<int>>q;
//像这样就可以建立一个大根堆,不过这样会多此一举,没啥用。

也可以使用构造函数重构,注意需要重载<,且必须重载<,重载其他运算符都无效。

struct node{
    int x,y;
    bool operator<(const node &o)const{
        if(x!=o.x)return x<o.x;// < 是大根堆 > 是小根堆
        return y<o.y;
    }
    node(int x_,int y_):x(x_),y(y_){}
};
std::priority_queue<node>q;

set

关于set

set的本质是二叉平衡树

set的作用

  1. 维护某个元素是否存在
  2. 查询大于等于/大于它的最小数字
  3. 维护本质不同的元素有几个

建立set

std::set<int>s;

set的操作

insert可以往set中插入一个元素,但set的元素不能重复

例如:

s.insert(1);
s.insert(4);
s.insert(2);
s.insert(2);//此时在插入一个2将什么都不会发生,就犹如把这一行给注释掉了。

set有指针,也可以使用for range遍历,输出时默认从小到大(升序)

s.size()s的大小

s.count(x)查询x是否存在,返回1和0

s.erase(x)删除x元素

set中的查找

set中也可以使用查找函数
s.lower_bounds.upper_bound

具体使用见下文

查找中的技巧

因为没有查找小于的函数,所以我们可以使用查找第一个大于等于前一个数,来查找第一个小于这个数的数。

例如想要在s中查找第一个小于4中的数,可以这样写:(注意,如果使用-1会编译错误,需要直接修改返回值,即--lower_bonud()

cout<<*(--s.lower_bonud(4));

那么同理可得,想要在s中查找第一个小于等于4的数就如下:

cout<<*(--s.upper_bonud(4));

注意

当出现越界是需要处理

auto ret=s.lower_bonud(1);
if(ret==s.begin()){
    //do sth.
}
else cout<<*(--s.lower_bound(1));

multiset

multiset其实就是可以有重复元素的set,用法也大致相同。

特殊的用法

见如下代码:

std::multiset<int>s;
s.insert(4);
s.insert(1);
s.insert(2);
s.insert(2);
for(auto i:s){
    std::cout<<i<<" ";
}
cout<<'\n';//此时会输出1 2 2 4
s.erase(2);
for(auto i:s){
    std::cout<<i<<" ";
}
cout<<'\n';//此时会输出1 4

所以s.erase(x)会删除所有的x,如果要只删掉一个x可以使用s.find(x),它返回的是一个迭代器,可以这样使用:

s.erase(s.find(x));//删除一个x

s.count(x)也有不同,它在multiset中返回的是x的数量,时间复杂度是\(O(log n+返回值大小)\)

bitset

bitset是一个01串。

建立

建立方式很简单,见如下代码。

std::bitset<x>bs;//x必须是一个在编译时确定的量,即常量

函数

s.count();//1的个数
s.all();//是否都是1
s.any();//是否有1
s.none();//是否都是0
s.set(1,1);//等价于s[1]=1;

lower_bound与upper_bound

lower_bound与upper_bound是两个函数

注意函数的返回值是地址(迭代器),输出请加上指针符*

作用

lower_bound可以返回第一个大于等于x的数

upper_bound可以返回第一个大于x的数

例如在vector中使用时可以用如下代码:

std::vector<int>a;
a.push_back(2);a.push_back(3);a.push_back(3);a.push_back(4);
for(int i=0;i<=5;i++){
    auto ret=std::lower_bound(a.begin(),a.end(),i);//>=
    auto rett=std::upper_bound(a.begin(),a.end(),i);//>
    if(ret!=a.end())std::cout<<*ret<<" ";
    else std::cout<<"NULL ";
    if(rett!=a.end())std::cout<<*rett<<"\n";
    else std::cout<<"NULL\n";
    //如果没有找到会返回a.end()
}

技巧

可以用返回值减去开始地址得到下标

例如,ret为lower_bound的返回值,那么

*ret=a[ret-a.begin()];

复杂度

O(\(log n\))

min max

//两个数的比较
int a=min(1,2),b=max(1,2);
//多个数的比较
int a=min({1,2,3,4,5}),b=max({1,2,3,4,5});//c++14
//数组中的比较
int a[5]={1,2,5,3,4};
cout<<*max_element(a,a+5)<<'\n';
cout<<*min_element(a,a+5)<<'\n';
//数组中的修改
nth_element(a,a+5,a+3);//将第4(3+1)小的数放在a+3的位置

next_permutation

没啥好说的,全排列。

#include<bits/stdc++.h>
using namespace std;
int main(){
    int a[3]={1,2,3};
    do{
        for(auto i:a)cout<<i<<" ";
        cout<<'\n';
    }while(next_permutation(a,a+3));
    return 0;
}

sort

快速排序和lambda表达式

#include<bits/stdc++.h>
using namespace std;
int main(){
    int a[3]={0,1,2};
    int b[3]={2,3,1};
    //想要按b[a[i]]<b[a[j]]排序
    //注意下面一行中[&](int x,int y),如果不加&,就只能访问被排序数组中(a)的元素,不能访问b数组
    sort(a,a+3,[&](int x,int y){//lambda表达式
        return b[x]<b[y];
    });
    for(auto i:a)cout<<i<<" ";
    return 0;
}
posted @ 2024-10-25 20:03  S_Z_Xcoco  阅读(45)  评论(0)    收藏  举报