# 十三. 标准模板库(STL)

标准模板库,其主要思想是结合C++的模板机制,设计出一系列的针对数据结构中具体问题的类模板和函数模板,所以也被称为是一个泛型化的数据结构和算法库

STL倡导泛型编程,形成了具有优秀、高效编码的模板库,成为了标准C++体系的一部分,使程序员将主要精力集中在高层逻辑而不是底层操作,极大地提高了编程效率

  • 迭代器

    可以理解为一种高级指针

    定义迭代器变量的格式容器类名称 <数据类型参数>:: iterator 迭代器变量;

    迭代器提供的基本操作和函数有:

    1. 获取当前被指向的元素,用“ * ”或“ -> ”表示;
    2. 指向下一个元素,迭代器的增量使用运算符 ++;
    3. 使用运算符“ == ”判断相等
    4. begin() 返回指向容器首元素的迭代器
    5. end() 返回容器末元素后一个位置的迭代器,注意不是末元素位置

# 1. 容器

# (1)顺序容器

vector,deque,list

存放元素都是线性的,具有很多共同操作

它们的差别在于访问元素的方式以及添加或删除元素相关操作的效率

以下为共同操作

函数名 功能说明
begin 返回容器中前端的迭代器
end 返回容器中末端的迭代器
rbegin 返回容器中前端的倒转迭代器
rend 返回容器中末端的倒转迭代器
insert(pos,e) 在容器中pos位置处插入元素e
erase(pos) 删除pos位置的元素
erase(begin,end) 删除[begin,end]区间中的元素
clear 删除容器内的所有元素
max_size 返回容器中的容量
size 返回容器当前包含元素的数量
empty 若容器为空(无元素),返回true;否则,返回false

根据不同要求,选择合适的容器,以提高效率

  • # vecter

    向量vector用于容纳不定长的线性序列,允许对各元素进行随机访问,可以理解为一个动态数组

    特点:

    1. 对序列元素可以快速、随机地访问,可以使用下标直接访问“[]”
    2. 末端插入和删除元素速度快,而在其他位置插入、删除需要移动大量元素,所以效率低
    3. 自己的函数:
    函数名 功能说明
    front 返回容器中首元素的引用
    back 返回容器中末端元素的引用
    push_back 向容器末端插入元素
    pop_back 删除末端元素

    :

    #include<iostream>
    #include<vector>        //包含头文件
    using namespace std;
    int main()
    {
        vector<int> v;     //定义v向量对象,vector为类模板,将其实例化为模板类,里面存放整型数据,定义对象名为v
        v.insert(v.begin(),1);//把1插入向量v首端           //v中为1
        v.insert(v.begin(),2);//把2插入向量v首端           //v中为2,1
        v.insert(v.end(),3);//把3插入向量v末端             //v中为2,1,3
        //前面为通用方法,后面为自带方法
        v.push_back(4);//向容器末端插入4                   //v中为2,1,3,4
        v.insert(v.begin()+3,5);//在第1+3位置插入5         //v中为2,1,3,5,4
        v.erase(v.begin()+2);//删除第1+2个元素             //v中为2,1,5,4
        //输出所有元素
        for(int i = 0;i < v.size();i++)//size()表示当前所有元素的个数
            cout<<v[i]<<"\t";
        cout<<"v.max_size:"<<v.max_size()<<endl;//容器可以存储元素的最大个数,与机器的环境有关
        //v中设计元素的个数
        cout<<"v.capacity:"<<v.capacity()<<endl;//目前v中可以存储元素的最大个数,可以动态增加,可能不是一个一个增加的
        return 0;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
  • # deque

    与vector相似,双端队列deque也是一种动态数组的形式,可以高效地在队尾插入、删除元素

    不同的是:还可以高效地在队头插入、删除元素

    特点:

    1. 可以通过[]下标形式来访问队列中的元素
    2. 两端插入、删除速度快、效率高,而在中间插入数据时开销大
    3. 自己的函数:
    函数名 功能说明
    push_front 插入数据到前端
    pop_front 删除前端数据
    push_back 向容器末端插入元素
    pop_back 删除末端元素

    :

    #include<iostream>
    #include<deque>
    using namespace std;
    int main()
    {
        deque<char> d;//定义d向量对象
        d.push_back('a');//向容器末端插入a          //d中为:a
        d.push_back('b');//向容器末端插入b          //d中为:a,b
        d.push_front('c');//向容器前端插入c          //d中为:c,a,b
        d.push_back('d');//向容器末端插入d          //d中为:c,a,b,d
        d.pop_back();//删除容器末端             //d中为:c,a,b
        d.pop_front();//删除容器末端             //d中为:a,b
        //输出v的所有元素
        for(int i = 0;i < d.size();i++)
            cout<<d[i]<<"\t";
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
  • # list

    链表容器list其内部数据结构实质上是一个双向链表

    特点:

    1. 不支持随机访问,即不支持“[]”运算符,只能用对应的迭代器来操作元素
    2. 任何位置插入、删除都不需要移动,所以速度快、效率高
    3. 自己的函数:
    函数名 功能说明
    push_back 插入数据到末端
    push_front 插入数据到前端
    splice(pos,a) 将链表a插入到当前链表pos之前
    splice(pos,a,posa) 将链表a在posa后的元素移到当前链表pos前
    splice(pos,a,abeg,aend) 将链表a在[abeg,aend]内的元素移到当前链表pos之前
    unique 删除链表中相邻的重复元素
    remove(x) 删除与x相等的元素
    sort 对链表排序
    reverse 逆转链表中元素的次序

    :

    #include<iostream>
    #include<list>
    using namespace std;
    int main()
    {
        list<double> l;             //定义l向量对象
        l.push_front(1.1);          //向容器前端插入1.1         l中为1.1
        l.push_front(5.5);          //向容器前端插入5.5         l中为5.5,1.1
        l.push_front(2.2);          //向容器前端插入2.2         l中为2.2,5.5,1.1
        l.push_back(3.3);           //向容器末端插入3.3         l中为2.2, 5.5, 1.1, 3.3
        
        list<double>::iterator it;  //定义list迭代器
        
        for(it = l.begin();it != l.end();it++)//输出l的所有元素
        {
            cout<<*it<<"\t";
        }
        
        l.sort();//排序                     l中为1.1, 2.2, 3.3, 5.5
        
        for(it = l.begin();it != l.end();it++)//输出l的所有元素
        {
            cout<<*it<<"\t";
        }
        
        cout<<l.size();             //l中元素的个数
        l.remove(3.3);              //删除l中3.3
        //输出l中的所有元素
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29

# (2)关联容器

关联容器的每个元素都有一个键值容器中的元素是按照键的取值升序排列

关联容器的内部实现是采用二叉平衡树,所以可以高效地查找、插入和删除,但不能实现任意位置的操作

左节点比根节点小,右节点比根节点大

  • # set

    1. set是一个元素集合,集合中的元素是按有序的方式储存,所以查找、插入和删除速度快
    2. set中没有重复的元素,但multiset中允许有重复的元素

    :

    #include<iostream>
    #include<set>
    #include<string>
    using namespace std;
    int main()
    {
        string name[] = {"Simon","Tony","Harry","John"};    //定义字符串数组
        //1  set<string> s;               //定义s向量对象
        //2  s.insert(name[0]);
        //3  s.insert(name[1]);
        //以上1,2,3可写成:
        set<string> s(name,name+4);  //将数组内所有元素都给它
        
        set<string>::iterator it;    //定义set迭代器
        for(it = s.begin();it != s.end();it++)//输出s的所有元素
        {
            cout<<*it<<"\t";
        }
        
        string search_name;    //输入查找的字符串
        cout<<"input search_name:"<<endl;
        cin>>search_name//按照输入的值进行查找
        
        it = s.find(search_name);    //查找
        
        if(it == s.end())//如果查找不到进行插入
        {
            cout<<"not find!"<<endl;
            s.insert(search_name);
            for(it == s.begin();it != s.end();it++)
                cout<<*it<<"\t";
        }
        else            //查找到则进行删除
        {
            cout<<"Find!"<<endl;
            s.erase(search_name);
        }
        
        for(it == s.begin();it != s.end();it++)//输出s的所有元素查看插入结果
            cout<<*it<<"\t";    
        
        return 0;
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
  • # map

    有点像映射

    map映射与set的主要区别:set的元素本身是键本身,而一个map是一个键值对序列,即(key,value)一对值。它提供基于key的快速检索能力,在一个map中key值是唯一的

    map提供双向迭代器,既有从前往后的迭代器iterator,也有从后往前的迭代器reverse_iterator

    :

    #include<iostream>
    #include<map>
    #include<string>
    using namespace std;
    int main()
    {
        string name[4] = {"Simon","Tony","Harry","John"};//定义字符串数组放姓名
        int id[4] = {1101,1102,1103,1104};//定义整型数组放学号
        map<string,int> n;//定义n向量对象
        for(int i = 0;i < 4;i++)//n[键值] = 元素值
        {
            n[name[i]] = id[i];
        }
        
        for(i = 0;i < 4;i++)//通过下标输出姓名和学号
        {
            cout<<name[i]<<"\t"<<n[name[i]]<<endl;
        }
        
        map<string,int>::iterator it;//定义map迭代器
        for(it = n.begin();it != n.end();it++)//采用迭代器输出
        {
            cout<<it->first<<"\t"<<it->second<<endl;
        }
        //采用下标输出和迭代器输出的顺序是不同的,因为键值对是按字符串的ASC11码的值的顺序进行存储的
    }
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
上次更新时间:: 2/9/2025, 9:12:58 PM