STL

基本概念

  • STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称。
  • STL 从广义上讲分为三类:algorithm(算法)、container(容器)和 iterator(迭代器),容器和算法通过迭代器可以进行无缝连接。几乎所有的代码都采用了模板类和模板函数的方式,这相比传统的函数和类组成的库来说提供了更好的代码重用机会。
  • 在C++标准中,STL被组织为下面13个头文件:<algorithm>、<deque>、<functional>、<vector>、<list>、<map>、<memory>、<numeric>、<queue>、<set>、<statck>和<utility>。
  • 优点:

    • STL是C++的一部分,不用额外安装什么,被内建在编译器之内
    • STL的一个重要特点是数据结构和算法分离。
    • 无需思考STL的具体实现过程,只要能够熟练使用STL就OK
    • STL具有高可重用性,高性能,高移植性,跨平台的优点。
      • 高可重用性:STL中几乎所有的代码都采用了模板和模板函数的方式实现
      • 高性能:如map可以高效地从十万条记录里面查找出指定的记录,因为map是采用红黑树的变体实现的。
      • 高移植性:在项目A上用STL编写的模块,可以移植到项目B上
      • 跨平台:如用windows的Visual Studio编写的代码可以在Mac OS的XCode上直接编译

容器

容器的分类

  • 序列式容器(Sequence containers)

    • 每个元素都有固定位置 —— 取决于插入时机和地点,和元素值无关
    • vector、deque、list、queue
  • 关联式容器(Associated containers)
    • 元素位置取决于特定的排序准则,和插入顺序无关
    • set、multiset、map、multimap
数据结构 描述 实现头文件
向量(vector) 连续存储的元素 <vector>
列表(list) 由节点组成的双向链表,每个节点包含一个元素 <list>
双队列(deque) 连续存储的指向不同元素的指针所组成的数组 <deque>
集合(set) 由节点组成的红黑树,每个节点都包含着一个元素,节点之间以某种作用与元素对的谓词排列,不会出现两个相同的元素 <set>
多重集合(multiset) 允许存在两个相同的元素的集合 <set>
栈(statck) 先进后出的值的排列 <statck>
对列(queue) 先进先出的值的排列 <queue>
优先队列(priority_queue) 元素的次序是由作用与所存储的值 对上的某种谓词决定的一种队列 <queue>
映射(map) 由键值对组成的集合,以某种作用于键 对上的谓词排列,不允许存在重复的键 <map>
多重映射(multimap) 允许存在重复的键 <map>

vector容器

  • 简介:

    • vector是将元素置于一个动态数组中加以管理的容器
    • vector可以随机存取元素(支持索引值直接存取,用[ ]操作符或at()方法)
    • vector尾部添加或移除元素非常快速,但是在中部或头部插入元素或移除元素比较费劲
  • vector对象的默认构造
    • vector采用模板类实现,vector对象的默认构造形式:

    

    int arr1[] = {1, 2, 3, 4, 5};
vector<int> v1(arr1,arr1 + 5); // 存储数组中的1到5
printVector(v1,"v1"); vector<int> v2(6,10); // 存储三个10
printVector(v2,"v2"); vector<int> v3(v1); // 拷贝
printVector(v3,"v3");
  • vector对象的带参数构造

    • vector(beg,end);  // 构造函数将数组 [beg, end)区间(实际是对应地址区间)中的元素赋值给本身。注意该区间是左闭右开的区间。
    • vector(n, elem);  // 构造函数将 n 个elem赋值给本身。
    • vector(const vector &vec);  // 拷贝构造函数

  

  • vector的赋值

    • vector.assign(beg, end);  // 将数组 [beg, end)区间(实际是对应地址区间)中的元素赋值给本身,注意该区间是左闭右开的
    • vector.assign(n, elem);   // 构造函数将 n 个elem赋值给本身。
    • vector & operator = (const vector &vec); // 重载等号操作符 (即调用等号)
    • vector.swap(vec);  // 两个vector的元素互换
  • vector的大小
    • vector.size();  // 返回容器中的元素个数
    • vector.empty(); // 判断容器是否为空
    • vector.resize(num);  // 重新指定容器的长度为num,若容器边长,则以默认值填充新位置,若容器变短,则删除超出末尾的元素。
    • vector.resize(num, elem);  // 设置默认值为elem
  • vector的访问
    • vector支持 [ ] 直接访问,但是当[ ]内的下标越界时,程序有可能异常终止,且系统不会报任何错误信息,导致问题排查变得困难。 使用vector时,不推荐使用 [ ] 访问,而是期内置的函数at(idx)
    • vec.at(idx); // 返回索引idx所指的数据,如果idx越界,抛出out_of_range异常
  • vector的插入
    • vector末尾的添加移除操作

      • vec.push_back(elem);  // 在vector末尾添加元素 elem
      • vec.pop_back();  // 移除vector末尾的元素
    • 在某位置插入
      • vec.insert(pos, elem);   // 在pos位置插入elem元素的拷贝,返回新数据的位置
      • vec.insert(pos, n, elem); // 在pos位置插入n 个elem数据,无返回值
      • vec.insert(pos, beg, end);  // 在pos位置插入[ beg, end )区间的数据,无返回值
#include "iostream"
#include "vector"
using namespace std; void printVector(vector<int> vec,string name);
void divideLine(); int main() {
int arr1[] = {1, 2, 3, 4, 5};
vector<int> v1(arr1,arr1 + 5); // 存储数组中的1到5
printVector(v1,"v1"); vector<int> v2(6,10); // 存储三个10
printVector(v2,"v2"); vector<int> v3(v1); // 拷贝
printVector(v3,"v3");
divideLine(); vector<int> vecA,vecB,vecC,vecD; int vArr[] = {1,2,3,4,5};
vecA.assign(vArr + 1,vArr + 3);
printVector(vecA,"vecA"); vecB.assign(6,6);
printVector(vecB,"vecB"); vecC = {2,4,6,8,10};
printVector(vecC,"vecC"); vecD.assign(9,9);
vecD.swap(vecC); // vecC 与 vecD 元素互换
printVector(vecC,"vecC");
printVector(vecD,"vecD");
divideLine(); vector<int> vec1(6,6);
vec1.resize(5); // 截断为长度5
printVector(vec1,"vec1");
vec1.resize(7,7); // 扩充长度为7,并且以7为默认值补充
printVector(vec1,"vec1"); divideLine(); //vector<int> vecAt(3,3);
//cout << vecAt[6] << endl;
//cout << vecAt.at(6) << endl; vector<int> vIns;
cout << "末尾插入或移除:" << endl;
vIns.push_back(6);
printVector(vIns,"vIns");
vIns.pop_back();
printVector(vIns,"vIns");
vIns.push_back(6);
vIns.push_back(7);
vIns.push_back(8);
vIns.push_back(9);
printVector(vIns,"vIns");
cout << "三种插入方式:" << endl;
vIns.insert((vIns.begin() + 2),100);
printVector(vIns,"vIns");
vIns.insert((vIns.begin() + 3),2,1000);
printVector(vIns,"vIns");
vIns.insert((vIns.begin() + 5),vIns.begin(),vIns.begin()+2);
printVector(vIns,"vIns"); return 0;
} void printVector(vector<int> vec,string name) {
cout << name << ":";
int length = vec.size();
cout << "[";
for (int i = 0; i < length; ++i) {
i == length -1 ? cout << vec.at(i) : cout << vec.at(i) << ",";
}
cout << "]" << endl;
} void divideLine() {
cout << "--------------------分割线--------------------" <<endl;
}

迭代器

  • 迭代器是一种检查容器内元素并且遍历容器内元素的数据类型
  • 作用:
    • 迭代器提供对一个容器中的对象的访问方法,并且定义了容器中对象的范围
  • 为了提高编程效率而开发
  • 每个容器中都实现了一个迭代器用于对容器中对象的访问,虽然每个容器中的迭代器的实现方式不一样,但是对于用户来说,操作方式是一致的,也就是通过迭代器统一了所有容器的访问方式
  • 访问当前元素的下一个元素我们可以通过迭代器自增进行访问。

vector容器的iterator类型

  • vector <int> :: iterator iter;  // 变量名为iter
  • vector 容器的迭代器属于随机访问迭代器:迭代器一次可以移动多个位置。
  • 成员函数:
    • begin() :返回指向容器中第一个元素的正向迭代器;如果是const类型容器,则该函数返回的是常量正向迭代器
    • end():返回指向容器最后一个元素之后一个位置的正向迭代器;如果是const类型容器,则该函数返回的是常量正向迭代器,通常和begin()函数搭配使用
    • erase():删除迭代器所在位置的元素

  改写前文中代码使用的打印vector函数,改为使用迭代器实现:

void printVector(vector<int> vec,string name) {
cout << name << ":";
cout << "["; //int length = vec.size();
/*for (int i = 0; i < length; ++i) {
i == length -1 ? cout << vec.at(i) : cout << vec.at(i) << ",";
}*/ // 改为使用迭代器实现
vector<int> :: iterator iter;
for (iter = vec.begin(); iter != vec.end(); iter++) {
iter == vec.end() -1 ? cout << *iter : cout << *iter << ",";
}
cout << "]" << endl;
}

迭代器失效

  • 插入元素后失效

    • 在插入元素后,vector要进行扩容操作,(当前连续存储空间不够)有可能会新开辟一片连续的空间来存储,此时原来的存储空间以及被释放,而迭代器任然指向原来的位置,导致迭代器失效,后续继续操作此迭代器可能会产生不可预知错误。
    • insert( ) 函数会返回一个新的有效迭代器,需要将旧迭代器重新赋值,使其生效。
  • 删除元素后失效 
    • 如下代码,本意是要将所有3删除,但是并没有全部删除;原因是vector在执行删除操作时,将元素删除删除后,后续元素补上原来的空位,而在如下代码中,在删除后,迭代器继续执行了++操作,就导致不能删除连续的相同元素。
    // 删除元素导致迭代器失效
vector<int> vec22 = {1,2,3,3,3,3,4,5};
for(vector<int>::iterator it = vec22.begin(); it != vec22.end(); it++) {
if(*it == 3) {
vec22.erase(it);
}
}
printVector(vec22,"vec22");

    • 修复这个bug很简单,有两种方法

      • 在执行删除操作后,执行 it --操作,使其位置不动。
      • 推荐) erase( )函数删除会返回删除元素后一个元素位置的有效迭代器,将 it 重新赋值为该有效迭代器即可
        • 注意:erase()函数返回的删除元素的后一个位置,所以在删除后不需要移动迭代器的位置否则会无法删除连续的元素。
  • 为防止出现迭代器失效,在使用插入或删除操作后,一定要使用插入和删除函数返回的有效迭代器重新赋值给迭代器
// 删除vector中的等于某个值的元素
void deleteElem(vector<int> &v, int num){
vector<int> ::iterator iter;
int count = 0;
for (iter = v.begin(); iter != v.end();){
if (*iter == num){
iter = v.erase(iter);
count++;
}
else{
iter++;
}
}
cout << "成功删除了" << count << "个" << num << endl;
}

C++ STL(标准模版库)—— vector 与 迭代器的更多相关文章

  1. STL(标准模板库)理论基础,容器,迭代器,算法

    基本概念 STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称.现然主要出现在C++中,但在被引入C++之前该技术就已经存在了很长的一段时间.   ...

  2. 把《c++ primer》读薄(3-2 标准库vector容器+迭代器初探)

    督促读书,总结精华,提炼笔记,抛砖引玉,有不合适的地方,欢迎留言指正. 标准库vector类型初探,同一种类型的对象的集合(类似数组),是一个类模版而不是数据类型,学名容器,负责管理 和 存储的元素 ...

  3. 算法笔记 第6章 C++标准模版库(STL)介绍 学习笔记

    6.1 vector的常见用法详解 vector:变长数组,长度根据需要而自动改变的数组 要使用vector,则需要添加vector头文件,即#include<vector>,还需要在头文 ...

  4. STL学习系列一:STL(标准模板库)理论基础

    STL(Standard Template Library,标准模板库)是惠普实验室开发的一系列软件的统称.现然主要出现在C++中,但在被引入C++之前该技术就已经存在了很长的一段时间. STL的从广 ...

  5. STL(标准模板库)基本概念

    一.什么是STL STL(Standard Template Library,标准模板库)的从广义上讲分为三类:algorithm(算法).container(容器)和iterator(迭代器),容器 ...

  6. STL标准模板库(简介)

    标准模板库(STL,Standard Template Library)是C++标准库的重要组成部分,包含了诸多在计算机科学领域里所常见的基本数据结构和基本算法,为广大C++程序员提供了一个可扩展的应 ...

  7. STL标准模板库介绍

    1. STL介绍 标准模板库STL是当今每个从事C++编程的人需要掌握的技术,所有很有必要总结下 本文将介绍STL并探讨它的三个主要概念:容器.迭代器.算法. STL的最大特点就是: 数据结构和算法的 ...

  8. C++ Templates STL标准模板库的基本概念

    STL标准库包括几个重要的组件:容器.迭代器和算法.迭代器iterator,用来在一个对象群集的元素上进行遍历操作.这个对象群集或许是一个容器,或许是容器的一部分.迭代器的主要好处是,为所有的容器提供 ...

  9. C++:标准模板库vector

    一:介绍 vector是C++标准模板库,是一个容器,底层是数组,为连续内存. 命名空间为std,所属头文件为<vector>   注意:不是<vector.h> vector ...

  10. STL标准模板库 向量容器(vector)

    向量容器使用动态数组存储.管理对象.因为数组是一个随机访问数据结构,所以可以随机访问向量中的元素.在数组中间或是开始处插入一个元素是费时的,特别是在数组非常大的时候更是如此.然而在数组末端插入元素却很 ...

随机推荐

  1. webpack4.15.1 学习笔记(八) — 缓存(Caching)

    目录 输出文件名(Output Filenames) 缓存第三方库 将 js 文件放到一个文件夹中 webpack 打包模块化后的应用程序,会生成一个可部署的 /dist目录,只要 /dist 目录中 ...

  2. microsoft office object版本对应offices版本

    1997年 Excel 97 Microsoft Excel 8.0 1999年 Excel 2000 Microsoft Excel 9.0 2001年 Excel XP Microsoft Exc ...

  3. oeasy教您玩转vim - 26 - 缩进设置

    ​ 缩进设置 回忆上节课内容 这次了解了颜色的细节 设置 256 色模式 :set t_Co=256 然后确定了具体的各种颜色 还可以生成网页 :TOhtml 还有什么好玩的么? ​ 缩进设置 ​ 在 ...

  4. .NET科普:.NET简史、.NET Standard以及C#和.NET Framework之间的关系

    最近在不少自媒体上看到有关.NET与C#的资讯与评价,感觉大家对.NET与C#还是不太了解,尤其是对2016年6月发布的跨平台.NET Core 1.0,更是知之甚少.在考虑一番之后,还是决定写点东西 ...

  5. 七天.NET 8操作SQLite入门到实战 - (3)第七天Blazor学生管理页面编写和接口对接

    前言 本章节的主要内容是完善Blazor学生管理页面的编写和接口对接. 七天.NET 8 操作 SQLite 入门到实战详细教程 第一天 SQLite 简介 第二天 在 Windows 上配置 SQL ...

  6. 【Java-GUI】03 事件监听

    --1.监听机制案例 简答理解:操作驱动程序执行 完整的操作体系:事件源.事件.监听器.注册监听 案例: 点击OK按钮,让上方的输入框写入一段字符 package cn.dzz; import jav ...

  7. 【设计模式 Design Pattern】【UML】建模语言

    什么是UML图? UML-Unified Modeling Language 统一建模语言,又称标准建模语言. 是用来对软件密集系统进行可视化建模的一种语言. UML的定义包括UML语义和UML表示法 ...

  8. 【Hibernate】Re01.5 API

    1.Session单表的CRUD操作 1.增加或者修改,使用同一个方法,或者下面的两个也行: 感觉多此一举... 2.删除方法,硬删除: 3.获取方法提供了两种,Get & Load get方 ...

  9. 大语言模型内部运行原理 | LLM | 词向量 | Transformer | 注意力机制 | 前馈网络 | 反向传播

    https://www.understandingai.org/p/large-language-models-explained-with https://arxiv.org/abs/1905.05 ...

  10. 【转载】 gym atari游戏的环境设置问题:Breakout-v0, Breakout-v4, BreakoutNoFrameskip-v4和BreakoutDeterministic-v4的区别

    版权声明:本文为CSDN博主「ok_kakaka」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/clksjx/ ...