浅浅的介绍一下STL

1.什么是STL

STL 全称 (Standard Template Library),就是标准模板库,说人话就是C++标准里帮我们写好了一些经常用到的东西,其中包括容器(就是存东西的)、算法(例如之前学过的sort )、迭代器(可以看成功能更强大的指针)。
灵活的运用STL,可以方便我们写代码,减少许多不必要的思维量(毕竟一大票东西别人都写好了,写的还比你自己写的好用)。比如 : sdnu1060 sdnu1090。
 
但是滥用 STL 也有风险:
1. STL里有很多竞赛不需要的附加功能,运行速度肯定会比手写慢,在竞赛中可能会因此得到 TLE
2. 容易出现一些奇奇怪怪的隐性BUG,并且还很难找到(所以这些东西手写也得会,语法糖吃多了不好)。
3. 考场上容易忘使用方法,或者混淆使用方法并且自以为正确并且样例看起来也确实正确。

2.容器(Containers)

2.1 vector
vector :不定长数组 ( 动态数组 ) 。 我们知道在C语言中,数组大小一旦确定就不能更改,但是有时候我们确实需要动态改变数组的大小,于是 C++ 中就提供了一个不定长数组。
头文件:#include<vector>
指定长度或初始值的初始化

int mian(){
    vector<int> num1;//定义了一个名为num1,大小为 0,存放int类型数据的数组
    vector<double> num2;//定义了一个名为num2,大小为0,存放double类型数据的数组
    vector<Node> num3;//还可以存放自己定义的结构体类型
    return 0;
}


int mian(){
    vector<int> a(n);//定义了长度为n的动态数组a,下标和一般数组一样,从0开始
    vector<int> b(n,0);//定义了长度为n的动态数组b,并且初值全为0
    vector<int> c(n.100);//定义了长度为n的动态数组c,并且初值全为100
    return 0;
}


int mian(){
   vector<int> a={1,4,2,7,5,8};//数组大小为6,元素顺序为1,4,2,7,5,8
   vector<int> b=a;//与一般数组不同,动态数组可以直接拷贝,而普通的数组不行哦
    return 0;
}                           //元素的初始化

定义二维数组


int mian(){
   vector<int> a[5];// 本质等于定义了5个 vector, 分别是a[0], a[1] ... a[4] 
                    // 显然这种方式是混合C的数组的,所以显然这个5就 不能改变了,但是a[0] ~ a[4]            
                       的大小是可以改变的 
                    // 这种写法只有列可以改变大小,行不能改变大小
    return 0;
}   

这里对于二维数组有个形象生动的比喻,以上面的动态二维数组为例,我们将用vector<int> 定义的5个vector.a[0]--a[4]看成一根葡萄藤上的5个节点,将每个vector.a里的元素个数看成每个节点下结的若干个葡萄,这样是不是就好理解多了,节点是不能改变的,而节点下结的葡萄个数却是可以动态增多的。

所以我们有下面的定义方式


int mian(){
   vector<vector<int>> a(5); // 这样就有一个 行列都可变长的二维数组了 
   vector<vector<int>> a(5,vector<int> (10, 0)); // 初始化列就等于又初始化一个 vector
                             //定义了一个二维数组,其中初始化有5个葡萄节点,节点数量可以改变,每 
                              个节点下初始化有10个葡萄,葡萄数量可以改变,每个葡萄重量初始化为0。
    return 0;
}  

这时候大家就会发现,如果要定义多维的数组就要嵌套多个vector,非常麻烦,因此C++ 17之后支持的初始化方式

vector a(5, vector<int>(10));

访问元素:基本和C数组一样,通过下标访问、遍历

vector<int> a(n);//定义一个长度为n的数组
for(int i=0;i<n;i++){
    cin>>a[i];    //这里循环输入和普通数组一样
}
int res=a[0];     //访问首个元素

C++还提供了智能指针,能自动按顺序访问所有元素(特别注意,sdnuoj系统非常古老,所以提交智能指针会pe)

vector<int> a(n);//定义一个长度为n的数组
for(int i:a){
    cout<<i<<'\n';
}    

//如果你甚至懒得想这个数组是什么类型的,还可以 用auto
for(auto i:a){
    cout<<i<<'\n';
}

另外STL里的容器也可以使用迭代器访问元素,所谓迭代器可以理解为一种更为强大的指针就行了。(为什么要用迭代器呢?因为STL里面的容器需要实现功能很多,传统指针不够用)

vector<int> a(n);
vector<int> :: iterator i = a.begin();//定义了一个vector<int>类型的迭代器,并且指向了a数组的开头
cout<< *i <<'\n';//输出i所指向的内容;

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

// 同样如果懒得写上面这一坨类名并且还有一堆不明含义 的冒号,也可以使用auto 
auto i = a.begin(); // 遍历同理也可以用这种 
for(auto i : a){
 cout << i << '\n'; 
}

此外关于vector的函数就太多了,这里浅浅的列举出一些常用的,建议用一个带有代码补全的编辑器,学会看 函数原型以及用户文档来了解。

附上C++的用户手册:https://cplusplus.com/reference/

 例题: P1066P1614

2.2 set( 集合 )
set中的元素不会重复,如果插入了重复的元素,会自动忽略该次插入操作,并且 set 里面的元素自动从小到大排序。
头文件以及定义
#include <set> 
set<int> st; // 定义一个名为set,存放int类型数据的集合 
set<int> st2 = st; //也可以使用类似vector一样的拷贝赋值
一些基本操作
set<int> st;
st.insert(5);
st.insert(0);st.insert(3);
st.insert(1);
ST.insert(3);
st.insert(5);//由于原先已经存入5了,所以这次存入会被忽略

cout << st.size() << '\n';   // 输出st的大 小,很明显是4 
cout << st.count(5) << '\n'; // count(x)查询x出现的次数,但是set里元素只能出 现一次, 
                             // 所以可以 用来判断x是否在x里出现

注意:set与vector不同,不能通过下标来访问,因此就必须使用迭代器或者智能指针

set<int> :: iterator i = st.begin();
cout<< *i << endl;//输出第一个元素
i = next(i);      //迭代器后移,访问下一个元素
cout<< *i <<endl; //输出下一个元素

//当然可以通过迭代器遍历输出
for(i=st.begin(); i!=st.end() ; i++){
    cout<< *i <<endl;
}

//或者智能指针
for(auto i : st){
    cout<< *i <<endl;
}

再来介绍一些关于set的函数

 set衍生来的一些容器:

unordered_set<int> a; // 无序集合,元素无序,但是只能出现一次 
multiset<int> b; //多重集合,可以存在多个元素
unordered_multiset<int> c //无序多重集合

例题:sdnu1209、sdnu1058

2.3 pair (二元组)

pair里面含有两个元素,可以看作是只有两个元素的结构体。pair只是一个简单二元组,所以没有特别的操作,不过重载了’<‘   运算符使得首先比较 first元素,嗦人话就是优先按照first 元素来比较大小, first 元素相同时在按 second元素来比较大小
头文件以及初始化
#include<utility> 
pair<int, int> p; // 定义了一个first元素为 int, second元素为int的二元组 
p = {5, 3}; // 讲first元素赋值为5, second 元素赋值为3(在一些老版本的编译器上可能用不了) 
            //如果需要将一个5和3结合成二元组,可以使用函数 make_pair(); 
p = make_pair(5, 3);

访问元素

pair<int, int> p = {5, 3};

 // 要访问第一个元素就使用p.first, 要访问第二个 元素就使用p.second; 

int a = p.first, b = p.second; 
                                // pair<int, int> 其实等价于下面的结构体 
                                struct pair{ 

                                    int first, second;
 
                                };

2.4 map(映射)

map 就类似数学上的函数。长这个样子-> map<int, int>mp 。可以看到 map 也有 first second 两个元素,我们把first叫做键值 (key) ,把 second 叫做值 (value) 。在 map里面,一个 key 对应一个 value ,类似函数里一个 x 对应一个 y。并且在map 里, x不能重复,自动按从小到大排序。
可以把 map 看成由一堆 pair 组成的 set
头文件以及初始化
#include<map>

map<int,int> mp;      //定义了一个int映射int的map;
map<int,string> mp;   //定义了一个string映射int的map;
map<char,int> mp;     //定义了一个char映射int的map;
map<int, node> mp     // 定义了一个int映射node的map(node是结构体)

基本操作

map<int,int> mp;
mp.insert(make_pair(1,2));        // 插入key为 1,value为2的映射
mp.insert({1,2});                 // 在C++11版本之后,可 以用花括号来生成结构体了

cout<< mp[1] <<endl;              //输出1的映射,显然是2

mp[1]=3;                          //把原先的1映射2,改成1映射3
cout<< mp[1] <<endl;              //显然这时候会输出3

cout<< mp[2]<<endl;               //如果原先没有定义2的映射,那么自动生成2映射0;
遍历map 以及两种智能指针
//遍历map
map<int, int> :: iterator i;
for(i = mp.begin() ; i!= mp.end(); i++){
    cout<< *i.first <<' ' << *i.second;
}


//智能指针
for( auto i: mp){
    cout<< i.first <<' ' << i.second;
}


//另一种智能指针
for(auto[x ,y] : mp){
    cout<< x << ' ' << y <<'\n' ;
}

这里再介绍一些其他关于map的操作

map 衍生来的一些容器
unorder_map<int, int> mp; // 无序
到这里常用的容器就基本结束了,还有一些可能会用到的容
器,感兴趣可以自行了解: bitset array tuple
例题:sdnu1058、sdnu1703
  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值