C++标准模板库(STL)的介绍与使用#2020-02-25

模板库(STL)属于C++标准库的一部分,定义并声明了标准模板。
STL是一套功能强大的 C++ 模板类。STL的目的是为了标准化组件,这样就不用重新开发,让后来者可以使用现成的组件。

1、STL六大组件:

容器(containers)、算法(algorithms)、迭代器(iterators)、函数对象(functors)、适配器(adapters)、分配器(allocators)。

六大组件的交互关系:
container(容器) 通过 allocator(配置器) 取得数据储存空间,algorithm(算法)通过 iterator(迭代器)存取 container(容器) 内容,functor(仿函数) 可以协助 algorithm(算法) 完成不同的策略变化,adapter(配接器) 可以修饰或套接 functor(仿函数)。

  • 容器(container)
    容器就是一种用来存放数据的对象。
    (1)容器是容器类实例化之后的一个具体的对象;
    (2)容器类是基于类模板(也就是STL)定义的,存放的数据类型是相同的;
    (3)容器可以自行扩展。它不需要你预先告诉它你要存储多少对象,只要你创建一个容器对象,并合理的调用它所提供的方法,所有的处理细节将由容器来自身完成。它可以为你申请内存或释放内存,并且用最优的算法来执行命令;
    (4)STL对定义的通用容器分三类:
    顺序性容器:vector、deque、list
    关联性容器:set、multiset、map、multimap
    容器适配器:stack、queue、
  • 算法(algorithm)
    算法作用于容器,包括对容器内容进行初始化,排序,搜索和转换等操作。
    STL算法分为四类:
    (1)非可变序列算法:不直接修改容器中内容。
    (2)可变序列算法:可以直接修改容器的内容。
    (3)排序算法:包含对序列的排序,合并,搜索和对有序序列的操作等算法那。
    (4)数值算法:对容器内容计算。
  • 迭代器(iterator)
    迭代器是一种对象,用来遍历STL容器中的部分或全部元素,每个迭代器对象代表容器中的确定的地址,所以可以认为迭代器其实就是用来指向容器中数据的指针,我们可以通过改变这个指针来遍历容器中的所有元素。
  • 函数对象(functor)
    重载函数调用操作符的类,其对象常称为函数对象(function object),即它们是行为类似函数的对象,也叫仿函数(functor),其实就是重载“()”操作符,使得类对象可以像函数那样调用。
    注意
    函数对象(仿函数)是一个类,不是一个函数。
    函数对象(仿函数)重载了”() ”操作符使得它可以像函数一样调用。
    分类
    假定某个类有一个重载的operator(),而且重载的operator()要求获取一个参数,我们就将这个类称为“一元仿函数”(unary functor);相反,如果重载的operator()要求获取两个参数,就将这个类称为“二元仿函数”(binary functor)。
    API 意义
算术类:
template<class T> T plus<T>	加法仿函数
template<class T> T minus<T>	减法仿函数
template<class T> T multiplies<T>	乘法仿函数
template<class T> T divides<T>	除法仿函数
template<class T> T modulus<T>	取模仿函数
template<class T> T negate<T>	取反仿函数
关系运算类:
template<class T> bool equal_to<T>	 等于
 template<class T> bool not_equal_to<T>	 不等于
 template<class T> bool greater<T>	 大于
 template<class T> bool greater_equal<T>	 大于等于
 template<class T> bool less<T>	 小于
 template<class T> bool less_equal<T>	 小于等于
逻辑运算类:
template<class T> bool logical_and<T>	 逻辑与
template<class T> bool logical_or<T>	逻辑或
template<class T> bool logical_not<T>	逻辑非
  • 适配器(adapter)
    c++中的适配器有三种:
    容器适配器:因为这些容器都是基于其他标准容器实现的所以叫做容器的适配器,具体的有stack,queue,priority_queue。默认的情况下,stack和queue基于deque而实现的,priority_queue在vector上实现的,可以根据第二个实参指定容器的类型,但一定要符合标准,queue要求要有push_front操作因此不能建立在vector上面,priority_front要求有随机访问的功能,因此建立在vector上面。优先级队列默认情况下是大顶堆,也就是大者优先级高,后面可以自定义优先级比较规则;
    迭代器适配器:包括三种reverse(逆向)适配器,insert(安插型)迭代器,stream(串流)适配器。
    reverse适配器:如rbegin(),rend()等。
    insert迭代器:是一种迭代器适配器,带有一个容器参数,并生成一个迭代器,提供了三种插入器back_inserter(容器),front_inserter(容器),inserter(容器,位置)。
    stream适配器:如ostream_iterator,istream_iterator。
    函数适配器:用于扩展一元和二元函数对象,如functor 函数对像等等。用于容器与算法之前的操作时使用。
  • 分配器(allocator)
    分配器就用于处理容器对内存的分配与释放请求。换句话说,分配器用于封装STL容器在内存管理上的低层细节。默认情况下,C++标准库使用其自带的通用分配器,但根据具体需要,也可自行定制分配器以替代之。

二、容器使用举例

1、vector
vector向量是一种顺序行容器。相当于数组,但其大小可以不预先指定,并且自动扩展。它可以像数组一样被操作,由于它的特性我们完全可以将vector 看作动态数组。
在创建一个vector 后,它会自动在内存中分配一块连续的内存空间进行数据存储,初始的空间大小可以预先指定也可以由vector 默认指定。当存储的数据超过分配的空间时vector 会重新分配一块内存块,但这样的分配是很耗时的,在重新分配空间时它会做这样的动作:
首先,vector 会申请一块更大的内存块;
然后,将原来的数据拷贝到新的内存块中;
其次,销毁掉原内存块中的对象(调用对象的析构函数);
最后,将原来的内存空间释放掉。

当vector保存的数据量很大时,如果此时进行插入数据导致需要更大的空间来存放这些数据量,那么将会大大的影响程序运行的效率,所以我们应该合理的使用vector。

  • 初始化vector对象的方式:
vector<T> v1;     // 默认的初始化方式,内容为空
vector<T> v2(v1);   // v2是v1的一个副本
vector<T> v3(n, i)   // v3中包含了n个数值为i的元素
vector<T> v4(n);   // v4中包含了n个元素,每个元素的值都是0
  • vector常用函数
empty():判断向量是否为空,为空返回真,否则为假
begin():返回向量(数组)的首元素地址
end(): 返回向量(数组)的末元素的下一个元素的地址
clear():清空向量
front():返回得到向量的第一个元素的数据
back():返回得到向量的最后一个元素的数据
size():返回得到向量中元素的个数
push_back(数据):将数据插入到向量的尾部
pop_back():删除向量尾部的数据
.....
  • 遍历方式
    vector向量支持两种方式遍历,因为可以认为vector是一种动态数组,所以可以使用数组下标的方式,也可以使用迭代器。
#include <iostream>
#include <vector>
#include <list>
#include <map>

using namespace std;

int main(void)
{
    vector<int> vec;

    vec.push_back(1);
    vec.push_back(2);
    vec.push_back(3);
    vec.push_back(4);
    vec.push_back(5);

    cout << "向量的大小:" << vec.size() << endl;

    // 数组下标方式遍历vector
    for (int i = 0; i < vec.size(); i++)
        cout << vec[i] << " ";
    cout << endl;

    // 迭代器方式遍历vector
    vector<int>::iterator itor = vec.begin();
    for (; itor != vec.end(); itor++)
        cout << *itor << " ";
    cout << endl;

    return 0;
}

2、list
双向链表,数据元素包括:指向前一个链表节点的前向指针、有效数据、指向后一个链表节点的后向指针
链表相对于vector向量来说的优点在于:
(a)动态的分配内存,当需要添加数据的时候不会像vector那样,先将现有的内存空间释放,在次分配更大的空间,这样的话效率就比较低了;
(b)支持内部插入、头部插入和尾部插入
缺点:
不能随机访问,不支持[]方式和vector.at()、占用的内存会多于vector(非有效数据占用的内存空间)

  • 初始化list对象的方式
list<int> L0;    //空链表
list<int> L1(3);   //建一个含三个默认值是0的元素的链表
list<int> L2(5,2); //建一个含五个元素的链表,值都是2
list<int> L3(L2); //L3是L2的副本
list<int> L4(L1.begin(),L1.end());    //c5含c1一个区域的元素[begin, end]。
  • list常用函数
begin():返回list容器的第一个元素的地址
end():返回list容器的最后一个元素之后的地址
rbegin():返回逆向链表的第一个元素的地址(也就是最后一个元素的地址)
rend():返回逆向链表的最后一个元素之后的地址(也就是第一个元素再往前的位置)
front():返回链表中第一个数据值
back():返回链表中最后一个数据值
empty():判断链表是否为空
size():返回链表容器的元素个数
clear():清除容器中所有元素
insert(pos,num):将数据num插入到pos位置处(pos是一个地址)
insert(pos,n,num):在pos位置处插入n个元素num
erase(pos):删除pos位置处的元素
push_back(num):在链表尾部插入数据num
pop_back():删除链表尾部的元素
push_front(num):在链表头部插入数据num
pop_front():删除链表头部的元素
sort():将链表排序,默认升序
......
  • 遍历方式
    双向链表list支持使用迭代器正向的遍历,也支持迭代器逆向的遍历,但是不能使用 [] 索引的方式进行遍历。
#include <iostream>
#include <vector>
#include <list>
#include <map>

using namespace std;

int main(void)
{
    list<int> l1;

    // 插入元素方式演示
    l1.push_front(1);            // 头部插入
    l1.push_back(2);             // 尾部插入
    l1.insert(l1.begin(), 3);    // 开始位置插入
    l1.insert(l1.end(), 4);        // 结束位置插入

    cout << "链表是否为空:" << l1.empty() << endl;
    cout << "list链表中元素个数:" << l1.size() << endl;
    cout << "list链表第一个元素:" << l1.front() << endl;
    cout << "list链表最后一个元素:" << l1.back() << endl;

    // 遍历链表正向
    list<int>::iterator itor = l1.begin();
    for (; itor != l1.end(); itor++)
        cout << *itor << " ";
    cout << endl;

    // 遍历链表逆向
    list<int>::reverse_iterator reitor = l1.rbegin();
    for (; reitor != l1.rend(); reitor++)
        cout << *reitor << " ";
    cout << endl;

    // 将链表排序
    l1.sort();
    itor = l1.begin();
    cout << "重新排序之后正向遍历:";
    for (; itor != l1.end(); itor++)
        cout << *itor << " ";
    cout << endl;

    // 清除容器中的所有元素
    l1.clear();
    cout << "清除容器所有元素之后大小:" << l1.size() << endl;

    return 0;
}

3、map
Map是STL的一个关联容器,它提供一对一(其中第一个称为关键字,每个关键字只能在map中出现一次,第二个称为该关键字的值)的数据处理能力,由于这个特性,它完成有可能在我们处理一对一数据的时候,在编程上提供快速通道。map内部自建一颗红黑树(一 种非严格意义上的平衡二叉树),这颗树具有对数据自动排序的功能,所以在map内部所有的数据都是有序的。map容器提供一种“键- 值”关系的一对一的数据存储能力。其“键”在容器中不可重复,且按一定顺序排列。

  • 初始化map对象的方式
map<int, string> m1 = { { 1, "guangzhou" }, { 2, "shenzhen" }, { 3, "changsha" } };   // 实例化一个map容器,还有3组数据
map<char, string> m2;             // 实例化一个空map容器
  • map常用函数
begin():返回容器第一个元素的迭代器
end():返回容器最后一个元素之后的迭代器
rbegin()rend()clera():清除容器中所有元素
empty():判断容器是否为空
insert(p1):插入元素  p1 是通过pair函数建立的映射关系对
insert(pair<char, string>('S', "shenzhen")): 插入元素
size():返回容器中元素的个数
count():返回指定键对应的数据的出现的次数
get_allocator():返回map的配置器
swap():交换两个map容器的元素
......
  • 遍历方式
    map容器支持迭代器正向方式遍历和迭代器反向方式遍历,同时也支持 [] 方式访问数据,[]中的索引值是键值。
#include <iostream>
#include <stdio.h>
#include <string>
#include <stdlib.h>
#include <vector>
#include <list>
#include <map>

using namespace std;

int main(void)
{
    map<int, string> m1 = { { 1, "guangzhou" }, { 2, "shenzhen" }, { 3, "changsha" } };
    map<char, string> m2;

    // 建立映射关系对
    pair<char, string> p1('G', "guangzhou");
    pair<char, string> p2('S', "guangzhou");
    pair<char, string> p3('C', "changsha");

    // 插入数据
    m2.insert(p1);
    m2.insert(p2);
    m2.insert(p3);

    cout << "map容器m1元素个数:" << m1.size() << endl;
    cout << "map容器m2元素个数:" << m2.size() << endl;

    // 采用 [] 方式打印数据
    cout << m1[1] << " " << m1[2] << " " << m1[3] << endl;
    cout << m2['G'] << " " << m2['S'] << " " << m2['C'] << endl;

    // 迭代器正向方式遍历
    map<int, string>::iterator itor = m1.begin();
    for (; itor != m1.end(); itor++)
    {
        cout << itor->first << ",";
        cout << itor->second << endl;
    }

    // 迭代器反向方式遍历
    map<char, string>::reverse_iterator reitor = m2.rbegin();
    for (; reitor != m2.rend(); reitor++)
    {
        cout << reitor->first << ",";
        cout << reitor->second << endl;
    }

    // 清空容器
    m1.clear();
    m2.clear();

    return 0;
}

参考博客:
C++标准模板库

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Rea1One

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值