• C++ STL & 标准库


    STL

             STL(标准模板库)是一套 C++ 模板类,提供了通用的模板类和函数,这些模板类和函数可以实现多种流行和常用的算法和数据结构,如向量、链表、队列、栈。

             C++ STL的核心包括三个组件:

    容器(Containers)用来管理某一类对象的集合。C++ 提供了各种不同类型的容器,比如 deque、list、vector、map 等。
    算法(Algorithms)算法作用于容器。它们提供了执行各种操作的方式,包括对容器内容执行初始化、排序、搜索和转换等操作。
    迭代器(iterators)迭代器用于遍历对象集合的元素。这些集合可能是容器,也可能是容器的子集。

             三个组件都带有丰富的预定义函数,帮助我们通过简单的方式处理复杂的任务。

    容器(vector )

    定义

             Vector是最常用的容器之一,是一个封装了动态大小数组的顺序容器(Sequence Container)。跟任意其它类型容器一样,它能够存放各种类型的对象。可以简单的认为,向量是一个能够存放任意类型的动态数组,因为其大小是根据实时更新而变化的。

               vector的定义如下:

    1. Vector<类型> 标识符
    2. Vector<类型> 标识符(最大容量)
    3. Vector<类型> 标识符(最大容量,初始所有值)
    4. Vector<类型> v(i,i+2); //得到i索引值为3以后的值
    5. Vector< vector< int> >v; //二维向量,这里最外的<>要有空格。否则在比较旧的编译器下无法通过

             例如:

    1. vector<int> v; // 储存int型的值
    2. vector<double> v; // 储存double型的值
    3. vector v; // 储存string型的值
    4. vector<struct> v; // 储存结构体或者类的值的值
    5. /* 可以定义vector数组 */
    6. vector<int> a[n]; // 储存int型的值
    7. vector<double> a[n]; // 储存double型的值

    特性 

             容器特性:

    • 顺序序列:顺序容器中的元素按照严格的线性顺序排序。可以通过元素在序列中的位置访问对应的元素。
    • 动态数组:支持对序列中的任意元素进行快速直接访问,甚至可以通过指针算述进行该操作。提供了在序列末尾相对快速地添加/删除元素的操作。
    • 内存分配感知(Allocator-aware):容器使用一个内存分配器对象来动态地处理它的存储需求。

    成员函数       

    构造函数
    1. vector(); //创建一个空vector
    2. vector(int nSize); //创建一个vector,元素个数为nSize
    3. vector(int nSize,const t& t); //创建一个vector,元素个数为nSize,且值均为t
    4. vector(const vector&); //复制构造函数
    5. vector(begin,end); //复制[begin,end)区间内另一个数组的元素到vector中
    增加函数
    1. /* 向量尾部增加一个元素X */
    2. void push_back(const T& x);
    3. /* 向量中迭代器指向元素前增加一个元素x */
    4. iterator insert(iterator it,const T& x);
    5. /* 向量中迭代器指向元素前增加n个相同的元素x */
    6. iterator insert(iterator it,int n,const T& x);
    7. /* 向量中迭代器指向元素前插入另一个相同类型向量的[first,last)间的数据 */
    8. iterator insert(iterator it,const_iterator first,const_iterator last);
    删除函数
    1. iterator erase(iterator it); //删除向量中迭代器指向元素
    2. iterator erase(iterator first,iterator last); //删除向量中[first,last)中元素
    3. void pop_back(); //删除向量中最后一个元素
    4. void clear(); //清空向量中所有元素
    遍历函数
    1. reference at(int pos); //返回pos位置元素的引用
    2. reference front(); //返回首元素的引用
    3. reference back(); //返回尾元素的引用
    4. iterator begin(); //返回向量头指针,指向第一个元素
    5. iterator end(); //返回向量尾指针,指向向量最后一个元素的下一个位置
    6. reverse_iterator rbegin(); //反向迭代器,指向最后一个元素
    7. reverse_iterator rend(); //反向迭代器,指向第一个元素之前的位置
    判断函数
    bool empty() const;          //判断向量是否为空,若为空,则向量中无元素
    大小函数
    1. int size() const; //返回向量中元素的个数
    2. int capacity() const; //返回当前向量所能容纳的最大元素值
    3. int max_size() const; //返回最大可允许的vector元素数量值
    4. /* 如果n小于当前容器的大小,则将内容减少到其前n个元素,并删除超出范围的元素(并销毁它们)*/
    5. void resize(size_type n);
    6. /**
    7. *如果n大于当前容器的大小,则通过在末尾插入所需数量的元素来扩展内容,以达到n的大小。
    8. *如果指定了val,则将新元素初始化为val的副本,否则将对它们进行值初始化。
    9. *如果n也大于当前容器容量,将自动重新分配已分配的存储空间
    10. */
    11. void resize(size_type n, const value_type& val);
    12. /**
    13. *表示预分配n个元素的存储空间,但不是真正的创建对象,
    14. *需要通过insert()或push_back()等操作创建对象。
    15. *调用reserve(n)后,若容器的capacity
    16. *若capacity>=n,capacity无变化。
    17. */
    18. void reserve(size_type n);
    resize() 和 reverse()区别

             容器调用resize()函数后,所有的空间都已经初始化了,所以可以直接访问。而reserve()函数预分配出的空间没有被初始化,所以不可访问。区别:

    • reserve()只修改capacity大小,不修改size大小,
    • resize()既修改capacity大小,也修改size大小。

              下面用实例进行说明:

    1. #include
    2. #include
    3. using namespace std;
    4. int main(void)
    5. {
    6. vector<int> v;
    7. cout<<"v.size() == " << v.size() << " v.capacity() = " << v.capacity() << endl;
    8. v.reserve(10);
    9. cout<5]<< endl;
    10. cout<<"v.size() == " << v.size() << " v.capacity() = " << v.capacity() << endl;
    11. v.resize(10);
    12. v.push_back(0);
    13. cout<<"v.size() == " << v.size() << " v.capacity() = " << v.capacity() << endl;
    14. return 0;
    15. }

             执行结果如下:

    v.size() == 0 v.capacity() = 0
    1735357008
    v.size() == 0 v.capacity() = 10
    v.size() == 11 v.capacity() = 20

    注: 对于:v.reserve(10) 后接着直接使用 [ ] 访问越界报错(内存是野的),这里直接用[ ]访问,vector 退化为数组,不会进行越界的判断。此时推荐使用 at(),会先进行越界检查,如下所示:

    cout<at(5)<< endl;

    v.size() == 0 v.capacity() = 0
    terminate called after throwing an instance of 'std::out_of_range'
      what():  vector::_M_range_check: __n (which is 5) >= this->size() (which is 0)

    相关引申:

             针对 capacity 这个属性,STL 中的其他容器,如 list、 map、set、deque,由于这些容器的内存是散列分布的,因此不会发生类似 realloc() 的调用情况,因此可以认为 capacity 属性针对这些容器是没有意义的,因此设计时这些容器没有该属性。在 STL 中,拥有 capacity 属性的容器只有 vector 和 string。

    capacity() 和 size() 的区别
    • size() :当前 vector 容器真实占用的大小,也就是容器当前存储的个数。
    • capacity() :容器可存储的最大总数,即预分配的内存空间。

             这两个属性分别对应两个方法:resize() 和 reserve()。       

    其他
    1. /* 交换两个同类型向量的数据 */
    2. void swap(vector&);
    3. /* 设置向量中前n个元素的值为x */
    4. void assign(int n,const T& x);//
    5. /* 向量中[first,last)中元素设置成当前向量元素 */
    6. void assign(const_iterator first,const_iterator last);

    实例

    pop_back() & push_back()

             在容器最后移除和插入数据:

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. int main()
    6. {
    7. vector<int> obj; // 创建一个向量存储容器 int
    8. for(int i=0;i<10;i++) // 依次在数组最后添加数据
    9. {
    10. obj.push_back(i);
    11. cout<"\t";
    12. }
    13. for(int j=0;j<5;j++) // 依次去掉数组最后一个数据
    14. {
    15. obj.pop_back();
    16. }
    17. cout<<"\n"<
    18. for(int k=0;ksize();k++) // size()返回容器中实际数据个数
    19. {
    20. cout<"\t";
    21. }
    22. return 0;
    23. }

             执行结果如下:

    0       1       2       3       4       5       6       7       8       9

    0       1       2       3       4

    clear()

             清除容器中所有数据:

    1. #include
    2. #include
    3. #include
    4. using namespace std;
    5. int main()
    6. {
    7. vector<int> obj;
    8. for(int i=0;i<10;i++)
    9. {
    10. obj.push_back(i);
    11. cout<"\t";
    12. }
    13. obj.clear();
    14. cout<
    15. for(int i=0;isize();i++)
    16. {
    17. cout<"\t";
    18. }
    19. cout<"size = "<size()<<", capacity = "<capacity();
    20. return 0;
    21. }

             执行结果如下:

    0       1       2       3       4       5       6       7       8       9

    size = 0, capacity = 16

    排序

             sort() 函数需要包含头文件: #include

    1. #include
    2. #include
    3. #include
    4. #include // 'sort()' and 'reverse()' was declared in this Header file
    5. using namespace std;
    6. int main()
    7. {
    8. vector<int> obj;
    9. obj.push_back(1);
    10. obj.push_back(2);
    11. obj.push_back(3);
    12. cout<<"由小到大:"<
    13. sort(obj.begin(),obj.end());
    14. for(int i=0;isize();i++)
    15. {
    16. cout<"\t";
    17. }
    18. cout<< endl <<"由大到小:"<
    19. reverse(obj.begin(),obj.end());
    20. for(int i=0;isize();i++)
    21. {
    22. cout<"\t";
    23. }
    24. return 0;
    25. }

             执行结果如下:

    由小到大:
    1       2       3

    由大到小:
    3       2       1

             如果想 sort 来降序,可重写 sort

    1. /* 升序排列,如果改为return a>b,则为降序 */
    2. bool compare(int a,int b)
    3. {
    4. return a< b;
    5. }
    6. /* 示例 */
    7. int a[20]={2,4,1,23,5,76,0,43,24,65},i;
    8. for(i=0;i<20;i++)
    9. {
    10. cout<< a[i]<< endl;
    11. }
    12. sort(a,a+20,compare);

             如下所示:

    1. #include
    2. #include
    3. #include
    4. #include // 'sort' and 'reverse' was declared in this Header file
    5. using namespace std;
    6. bool compare(int a,int b)
    7. {
    8. return a > b;
    9. }
    10. int main()
    11. {
    12. vector<int> obj;
    13. obj.push_back(1);
    14. obj.push_back(2);
    15. obj.push_back(3);
    16. cout<<"由小到大:"<
    17. sort(obj.begin(),obj.end());
    18. for(int i=0;isize();i++)
    19. {
    20. cout<"\t";
    21. }
    22. cout<< endl <<"由大到小:"<
    23. sort(obj.begin(),obj.end(),compare); //sort 来降序
    24. for(int i=0;isize();i++)
    25. {
    26. cout<"\t";
    27. }
    28. return 0;
    29. }
    直接数组访问&迭代器访问
    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. int main()
    7. {
    8. vector<int> obj;
    9. for(int i=0;i<10;i++)
    10. {
    11. obj.push_back(i);
    12. }
    13. // 方法一:直接数组访问
    14. cout<<"直接利用数组:"<<"\t";
    15. for(int i=0;i<10;i++)
    16. {
    17. cout<"\t";
    18. }
    19. // 方法二:迭代器访问
    20. cout<
    21. cout<<"利用迭代器:"<<"\t";
    22. vector<int>::iterator it;
    23. for(it=obj.begin();it!=obj.end();it++)
    24. {
    25. cout<<*it<<"\t";
    26. }
    27. return 0;
    28. }

             执行结果如下:

    直接利用函数:  0       1       2       3       4       5       6       7       8       9
    利用迭代器:     0       1       2       3       4       5       6       7       8       9

    二维数组两种定义方法

             假设定义一个二维数组obj[5][6],两种定义方法的结果一样:

    方法一
    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. int main()
    7. {
    8. int N=5,M=6; // 定义二维动态数组大小5行为5行6列,值默认全为0
    9. vector< vector<int> > obj(N); // 开辟行
    10. for(int i=0;isize();i++)
    11. {
    12. obj[i].resize(M); // 开辟行
    13. }
    14. for(int i=0;isize();i++) // 赋值,并输出二维动态数组
    15. {
    16. for(int j=0;jsize();j++)
    17. {
    18. obj[i][j]=i+j;
    19. cout<"\t";
    20. }
    21. cout<
    22. }
    23. return 0;
    24. }
    方法二
    1. #include
    2. #include
    3. #include
    4. #include
    5. using namespace std;
    6. int main()
    7. {
    8. int N=5,M=6; // 定义二维动态数组大小5行为5行6列,值默认全为0
    9. /* 创建一个vector,元素个数为N,且值均为一个元素个数为M的vector(M) */
    10. vector< vector<int> > obj(N,vector<int>(M));
    11. for(int i=0;isize();i++) // 赋值,并输出二维动态数组
    12. {
    13. for(int j=0;jsize();j++)
    14. {
    15. obj[i][j]=i+j;
    16. cout<"\t";
    17. }
    18. cout<
    19. }
    20. return 0;
    21. }

             输出结果为:

    0       1       2       3       4       5
    1       2       3       4       5       6
    2       3       4       5       6       7
    3       4       5       6       7       8
    4       5       6       7       8       9

    标准库

             C++ 标准库可以分为两部分:

    • 标准函数库: 由通用的、独立的、不属于任何类的函数组成的。它继承自 C 语言。
    • 面向对象类库: 这个库是类及其相关函数的集合。

             C++ 标准库包含了所有的 C 标准库,为了支持类型安全,做了一定的添加和修改。

    标准函数库

             标准函数库分为以下几类:

    • 输入/输出 I/O
    • 字符串和字符处理
    • 数学
    • 时间、日期和本地化
    • 动态分配
    • 其他
    • 宽字符函数

    面向对象类库

             面向对象类库定义了大量支持一些常见操作的类,比如输入/输出 I/O、字符串处理、数值处理。面向对象类库包含以下内容:

    • 标准的 C++ I/O 类
    • String 类
    • 数值类
    • STL 容器类
    • STL 算法
    • STL 函数对象
    • STL 迭代器
    • STL 分配器
    • 本地化库
    • 异常处理类
    • 杂项支持库

  • 相关阅读:
    局部线性嵌入(Locally Linear Embedding, LLE)
    Electron打包Vue踩坑记录
    【软件工程】四、编码 & 维护
    python 基础语法 (常常容易漏掉)
    R实现动态条件相关模型与GARCH模型结合研究中美股市动态相关性(DCC-GARCH模型)
    java毕业设计超市购物数据管理系统mybatis+源码+调试部署+系统+数据库+lw
    网络安全笔记 -- 文件操作(文件下载读取)
    valgrind,memcheck的使用
    Nmap使用教程图文教程(超详细)
    redis的常用基础类型及操作
  • 原文地址:https://blog.csdn.net/weixin_60461563/article/details/132859978