C++之STL整理(1)之STL、vector、map、set数据结构初识

C++之STL整理(1)之STL、vector、map、set数据结构初识

注:整理一些突然学到的C++知识,随时mark一下
例如:忘记的关键字用法,新关键字,新数据结构


C++ 的 STL

  • C++之STL整理(1)之STL、vector、map、set数据结构初识
  • 一、STL概要,初识STL
    • 1、STL之容器
      • (1)序列式容器
      • (2)关联式容器
    • 2、算法
    • 3、迭代器与遍历
      • (1)对vector的遍历
      • (2)对map的遍历
      • (3)对set的遍历
    • 4、仿函数
    • 5、适配器
    • 6、空间配置器
  • 总结


提示:本文为 C++ 中 vector、map、set的写法和举例


一、STL概要,初识STL

  STL,即Standard Template Library,标准模板库,是C++标准库的一个重要组成部分。它是一个可复用的封装好的组件库,同时也是一个包罗数据结构与算法的软件框架。STL为C++程序员们提供了一个可扩展的应用框架,高度体现了软件的封装性与可复用性。

STL包含了诸多在计算机科学领域里所常用的数据结构基本算法,提供了许多通用的模板类和函数,用于实现常用的数据结构和算法。STL的一个重要特点是数据结构和算法的分离,它允许程序员编写通用的代码,即可适用于不同的数据类型,而不必为每种类型编写不同的代码。

STL的六大组件包括容器(Containers)、迭代器(Iterators)、算法(Algorithms)、仿函数(Functors)、适配器(Adapters)和空间配置器(Allocators)

其中,
容器负责存储和管理数据,每种容器相当于定义好的一个反映数据结构的类(模板类):如字符串(string)、向量(vector)、列表(list)、双端队列(deque)、栈(stack)、队列(queue)、优先队列(priority_queue)、集合(set)、映射(map)等。
迭代器则用于遍历容器中的元素。
算法是对容器中的数据进行操作的函数,分为质变算法和非质变算法
仿函数和行为类似于函数的对象,可以作为算法的参数以定制算法的行为。
适配器用于修改容器或迭代器的接口以提供不同的功能。
空间配置器则负责内存的分配和释放。

1、STL之容器

容器:存储数据的数据结构类,如vector、deque、list等,C++的string数据结构也是一个封装好的容器。

算法:对容器中的数据进行操作的函数模板,如排序、查找等。

迭代器:提供一种方法来访问容器中的元素。

仿函数:行为类似函数的对象,可以作为算法的参数来定制算法的行为。

适配器:用于修改容器或迭代器的接口,以提供不同的功能。

空间配置器:负责内存分配和释放的组件,通常不需要直接操作。

(1)序列式容器

序列式容器中的元素按照插入顺序进行存储

Vector容器:又叫动态数组,支持随机访问。

#include <vector>  
#include <iostream>  int main() {  std::vector<int> vec = {1, 2, 3, 4, 5};  for (const auto& element : vec) {  std::cout << element << " ";  }  return 0;  
}

Deque容器:双端队列,支持在头部和尾部进行插入和删除操作。

#include <deque>  
#include <iostream>  int main() {  std::deque<int> deq = {1, 2, 3, 4, 5};  deq.push_front(0); // 在头部插入元素  deq.push_back(6); // 在尾部插入元素  for (const auto& element : deq) {  std::cout << element << " ";  }  return 0;  
}

List容器:双向链表,支持在任意位置进行插入和删除操作。

#include <list>  
#include <iostream>  int main() {  std::list<int> lst = {1, 2, 3, 4, 5};  lst.push_front(0); // 在头部插入元素  lst.push_back(6); // 在尾部插入元素  for (const auto& element : lst) {  std::cout << element << " ";  }  return 0;  
}

(2)关联式容器

关联式容器中的元素通过关键字进行存储和访问。关联式容器是非线性的树结构,更准确的说是二叉树结构。各元素之间没有严格的物理上的顺序关系,也就是说元素在容器中并没有维持元素置入容器时的逻辑顺序

Set/multiset容器:集合,存储唯一或重复的元素。

#include <set>  
#include <iostream>  int main() {  std::set<int> s = {3, 1, 4, 1, 5, 9, 2, 6, 5, 3, 5};  for (const auto& element : s) {  std::cout << element << " ";  }  return 0;  
}

Map/multimap容器:键值对集合,存储不重复/重复的键及其对应的值。

#include <map>  
#include <iostream>  int main() {  std::map<std::string, int> m = {{"Alice", 25}, {"Bob", 30}, {"Charlie", 35}};  for (const auto& pair : m) {  std::cout << pair.first << ": " << pair.second << std::endl;  }  return 0;  
}

2、算法

质变算法
质变算法会改变容器内元素的内容。

拷贝算法:例如std::copy。

#include <vector>  
#include <algorithm>  
#include <iostream>  
#include <iterator>  int main() {  std::vector<int> src = {1, 2, 3, 4, 5};  std::vector<int> dst(src.size());  std::copy(src.begin(), src.end(), dst.begin());  for (const auto& element : dst) {  std::cout << element << " ";  }  return 0;  
}

非质变算法
非质变算法不会改变容器内元素的内容。

查找算法:例如std::find。
继续上面的内容讲解,我们来看非质变算法的一个例子——std::find。

#include <vector>  
#include <algorithm>  
#include <iostream>  int main() {  std::vector<int> vec = {1, 2, 3, 4, 5};  auto it = std::find(vec.begin(), vec.end(), 3); // 查找值为3的元素  if (it != vec.end()) {  std::cout << "Found: " << *it << std::endl;  } else {  std::cout << "Not found" << std::endl;  }  return 0;  
}

在这个例子中,std::find算法在vec容器中查找值为3的元素,并返回一个迭代器指向找到的元素。如果找不到,则返回end()迭代器。

3、迭代器与遍历

迭代器提供了一种方法来遍历容器中的元素。上面的算法例子中已经展示了如何使用冒号遍历,当然数组可以用[]遍历,STL提供的新的遍历方法:使用迭代器。迭代器类似于指针,但提供了更安全的访问方式。STL提供了不同类型的迭代器,如输入迭代器、输出迭代器、前向迭代器、双向迭代器、随机访问迭代器等,每种类型支持不同的操作集。它使得程序员能够遍历容器(如vector、map、set等)中的元素,同时隐藏了底层数据结构的实现细节。迭代器就像是指向容器中元素的指针或引用,但它比指针更加类型安全,并且可以处理不同类型的容器。
语法是T<类>::iterator 迭代器指针名字 =
begin()这个接口返回一个指向容器第一个元素的迭代器。end()这个接口返回一个指向容器“尾后”位置的迭代器。注意,这不是容器的最后一个元素,而是最后一个元素再之后的位置。对于空容器,begin() 返回的迭代器与 end() 返回的迭代器是相等的。

下面是对vector、map和set使用迭代器进行遍历的示例代码:

(1)对vector的遍历

#include <iostream>
#include <vector>int main() {std::vector<int> vec = {1, 2, 3, 4, 5};// 使用迭代器遍历vectorfor (std::vector<int>::iterator it = vec.begin(); it != vec.end(); ++it) {std::cout << *it << " ";}std::cout << std::endl;// 使用基于范围的for循环遍历vector(C++11及以后)for (int val : vec) {std::cout << val << " ";}std::cout << std::endl;return 0;
}

(2)对map的遍历

#include <iostream>
#include <map>int main() {std::map<std::string, int> myMap = {{"apple", 1}, {"banana", 2}, {"cherry", 3}};// 使用迭代器遍历mapfor (std::map<std::string, int>::iterator it = myMap.begin(); it != myMap.end(); ++it) {std::cout << it->first << ": " << it->second << std::endl;}// 使用基于范围的for循环遍历map(C++11及以后)for (const auto& kv : myMap) {std::cout << kv.first << ": " << kv.second << std::endl;}return 0;
}

(3)对set的遍历

#include <iostream>
#include <set>int main() {std::set<int> mySet = {1, 3, 5, 7, 9};// 使用迭代器遍历setfor (std::set<int>::iterator it = mySet.begin(); it != mySet.end(); ++it) {std::cout << *it << " ";}std::cout << std::endl;// 使用基于范围的for循环遍历set(C++11及以后)for (int val : mySet) {std::cout << val << " ";}std::cout << std::endl;return 0;
}

在上面的代码中,可以看到对于vector、map和set,我们都可以使用传统的迭代器进行遍历,也可以使用C++11及以后版本的基于范围的for循环进行遍历。基于范围的for循环更加简洁,易于理解。但需要注意的是,基于范围的for循环在遍历map时,返回的是键值对(key-value pair),而不是单独的键或值。
注意map和set不支持用数组符号[]来遍历和索引。

4、仿函数

仿函数是行为类似于函数的对象。它们可以像函数一样被调用,并可以作为算法的参数,以定制算法的行为,一般配合 <algorithm> 使用。例如,std::less<T>是一个仿函数,用于比较两个对象是否一个小于另一个。

#include <vector>  
#include <algorithm>  
#include <iostream>  struct IsEven {  bool operator()(int n) const {  return n % 2 == 0;  }  
};  int main() {  std::vector<int> vec = {1, 2, 3, 4, 5};  vec.erase(std::remove_if(vec.begin(), vec.end(), IsEven()), vec.end());  for (const auto& element : vec) {  std::cout << element << " ";  }  return 0;  
}

在这个例子中,我们定义了一个仿函数IsEven,它接受一个整数并检查它是否为偶数。然后,我们使用std::remove_if算法和IsEven仿函数来移除vec中所有的偶数。

5、适配器

适配器用于修改容器或迭代器的接口,以提供不同的功能。例如,std::stack和std::queue就是基于std::dequestd::list等容器的适配器,它们提供了栈和队列的接口。

#include <stack>  
#include <iostream>  int main() {  std::stack<int> stk;  stk.push(1);  stk.push(2);  stk.push(3);  while (!stk.empty()) {  std::cout << stk.top() << " ";  stk.pop();  }  return 0;  
}

在这个例子中,我们使用了std::stack适配器来创建一个栈,并使用其提供的push、pop和top等方法来操作栈。

6、空间配置器

空间配置器负责内存的分配和释放。在STL中,它通常被封装起来,不需要直接操作。空间配置器允许STL库更高效地管理内存,特别是在大量小对象的情况下。

总结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/782945.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flutter开发的Web应用 构建及部署 标准流程指南

前言 Flutter是Google推出的跨平台开发框架&#xff0c;支持多种平台&#xff1a;Windwos&#xff0c;Mac&#xff0c;iphone&#xff0c;Android&#xff0c;Web&#xff0c;Linux&#xff0c;甚至经过一些折腾还可以支持树莓派&#xff0c;十分强大&#xff0c;笔者曾写过一…

FDM3D打印系列——手涂水性漆和补土

大家好&#xff0c;我是阿赵。   继续探索FDM3D打印。这次要打印的是拳皇系列的经典角色&#xff0c;八神庵&#xff1a;   上次那个卢卡尔打印的尺寸有点小&#xff0c;为了配合着卢卡尔的高度&#xff0c;所以这次这个八神庵也打印的特别的小&#xff1a;   特别小的…

C语言 键盘输入与屏幕输出——数据的格式化屏幕输出

目录 顺序结构 C语言如何实现数据的输入和输出&#xff1f; 数据的格式化屏幕输出 printf&#xff08;&#xff09;格式字符 printf&#xff08;&#xff09;的格式修饰符 顺序结构 一般而言&#xff0c;顺序结构程序涉及如下三个基本操作&#xff1a; *输入数据 *处理数…

C++STLmap,set

我最近开了几个专栏&#xff0c;诚信互三&#xff01; > |||《算法专栏》&#xff1a;&#xff1a;刷题教程来自网站《代码随想录》。||| > |||《C专栏》&#xff1a;&#xff1a;记录我学习C的经历&#xff0c;看完你一定会有收获。||| > |||《Linux专栏》&#xff1…

什么是公网IP?

公网IP&#xff0c;即公开网络IP地址&#xff0c;是指在互联网中公开可见、可访问的IP地址。每个设备在连接互联网时&#xff0c;都需要一个唯一的公网IP地址&#xff0c;以便其他设备可以定位并与之通信。 尽管公网IP在网络通信中具有重要作用&#xff0c;但它也带来了一些安全…

在GitHub上上传项目(Idea)

repository创建好后&#xff0c;GitHub会提示相应的命令 在Idea的终端执行这些命令&#xff0c;就OK了 在GitHub上查看&#xff0c;已经上传成功

【Hello,PyQt】QTextEdit和QSplider

PyQt5 是一个强大的Python库&#xff0c;用于创建图形用户界面&#xff08;GUI&#xff09;。其中&#xff0c;QTextEdit 控件作为一个灵活多用的组件&#xff0c;常用于显示和编辑多行文本内容&#xff0c;支持丰富的格式设置和文本操作功能。另外&#xff0c;QSlider 控件是一…

JavaScript高级 —— 学习(二)

目录 一、深入对象 &#xff08;一&#xff09;创建对象三种方式 1.利用对象字面量创建 2.利用 new Object() 创建 3.利用构造函数创建 &#xff08;二&#xff09;利用构造函数创建对象 1.构造函数介绍 2.约定 3.实例化执行过程 &#xff08;三&#xff09;实例成员…

git命令-项目使用

项目中用到的git命令&#xff0c;记录下来&#xff0c;后续项目可以直接用 配置命令 一次性设置&#xff1a; git config --global user.name "Your Name" git config --global user.email "youremailaddress.com"git config --global alias.pl "pu…

【React】React AJAX

在React中使用AJAX&#xff08;Asynchronous JavaScript and XML&#xff09;是一种常见的做法&#xff0c;用于从服务器获取数据并在组件中显示。尽管AJAX的名字中包含了XML&#xff0c;但现在更多地使用JSON&#xff08;JavaScript Object Notation&#xff09;作为数据交换格…

opengl草稿复习,承上启下(一)

目录 1、链接文件夹中的cpp 2、链接资源到输出目录 3、多编译目标 4、cmakelist添加库 4、添加glfw和glad 5、glfw运行 6、NDC、VBO、VAO 7、渐变三角形 8、渲染两个三角形 9、渲染两个三角形&#xff0c;同时基于原来颜色进行渐变 10、三角形渲染模块化 11、纹理渲…

Python API(happybase)操作Hbase案例

一、Windows下安装Python库&#xff1a;happybase pip install happybase -i https://pypi.tuna.tsinghua.edu.cn/simple 二、 开启HBase的Thrift服务 想要使用Python API连接HBase&#xff0c;需要开启HBase的Thrift服务。所以&#xff0c;在Linux服务器上&#xff0c;执行如…

Kerberos 认证 javax.security.auth.logon.LoginException:拒绝链接 (Connection refused)

kerberos 服务重启之后异常 项目中用到了hive 和hdfs &#xff0c;权限认证使用了Kerberos&#xff0c;因为机房异常&#xff0c;导致了Kerberos 服务重启&#xff0c;结果发现本来运行正常的应用服务hive 和hdfs 认证失败&#xff0c;报错信息是 典型的网络连接异常 排查思路…

软考 - 系统架构设计师 - 架构风格

软件架构风格是指描述特定软件系统组织方式的惯用模式。组织方式描述了系统的组成构件&#xff0c;以及这些构件的组织方式&#xff0c;惯用模式指众多系统所共有的结构和语义。 目录 架构风格 数据流风格 批处理架构风格 管道 - 过滤器架构风格 调用 / 返回风格 主程序…

动手学机器学习初探机器学习+习题

初探机器学习 “两只手”代表的是人工智能可以做的两大类任务&#xff0c;即预测与决策。 “四条腿”则代表支撑人工智能的四大类科学技术&#xff0c;包括搜索、推理、学习和博弈。 非参数化模型&#xff08;nonparametric model&#xff09;&#xff1a;与参数化模型相反&…

二、分布式事务

目录 二、分布式事务2.1 什么是分布式事务2.2 分布式事务产生的背景2.3 分布式事务产生的场景2.4 分布式事务理论4.1 CAP理论4.2 Base理论 5、分布式事务的解决方案 二、分布式事务 2.1 什么是分布式事务 一组操作会产⽣多个数据库session会话 此时就会出现分布式事务 2.2 分…

PTA----->幸运数字

一&#xff0c;题目&#xff1a; Rain Sure同学定义了幸运数字——如果一个正整数n是幸运数字&#xff0c;那么当且仅当n和(n1)/2都是素数。 现在给定q次查询&#xff1a; 第i次询问给定两个正整数li​,ri​&#xff0c;请你求出在区间[li​,ri​]中有多少个数字是幸运数字。…

我的第一个 VTK 程序

我的第一个 VTK 程序 我的第一个 VTK 程序VTK 可视化流程源程序运行结果 我的第一个 VTK 程序 环境&#xff1a; Visual Studio 2022 CommumityQt 6.2.3 MSVC2019 64位VTK 9.3.0 不会Cmake编译VTK库&#xff1f;看这个&#xff1a;使用 Cmake 对 VTK-9.3.0 进行编译 不会在…

代码随想录算法训练营第二十五天|17.电话号码的字母组合、39.组合总和

文档链接&#xff1a;https://programmercarl.com/ LeetCode17.电话号码的字母组合 题目链接&#xff1a;​​​​​​​​​​​​​​https://leetcode.cn/problems/letter-combinations-of-a-phone-number/ 思路&#xff1a; 理解本题后&#xff0c;要解决如下三个问题&…

Apache Hive的基本使用语法(一)

一、数据库操作 创建数据库 create database if not exists myhive;查看数据库 use myhive; desc database myhive;创建数据库并指定hdfs存储 create database myhive2 location /myhive2;删除空数据库&#xff08;如果有表会报错&#xff09; drop database myhive;…