STL补充:STL中遵循的左闭右开原则/STL随机访问

文章目录

    • 左闭右开原则
      • 示例:
      • 示例中erase的用法
      • 不能写成s.erase(s.begin()+left)的原因
    • STL中支持随机访问的迭代器

左闭右开原则

在 C++ 中,容器(如 vectorsetmap 等)的迭代器都遵循左闭右开的原则。

也就是说,对于任何容器 cc.begin() 返回的迭代器指向容器的第一个元素,而 c.end() 返回的迭代器指向容器的“尾后”元素,也就是最后一个元素的下一个位置

所以, c.end() 不指向任何有效元素,不能解引用得到元素,通常只作为范围结束的标志。

例如,下面的代码是遍历一个 vector 的标准方法:

vector<int> v = {1, 2, 3, 4, 5};
for(auto it = v.begin(); it != v.end(); ++it) {cout << *it << endl;
}

在这个例子中,v.begin() 返回的迭代器指向第一个元素 1v.end() 返回的迭代器指向尾后位置。我们一直迭代到 it 等于 v.end() 时停止,这时 it 已经不再指向任何有效元素。这就是左闭右开原则在 C++ 容器中的应用。

如果我们需要访问最后一个元素,应该用**反向迭代器*s.rbegin()**来实现。

示例:

//leetcode 6911.不间断子数组
class Solution {
public:long long continuousSubarrays(vector<int> &nums) {long long ans = 0;multiset<int> s;int left = 0;for (int right = 0; right < nums.size(); right++) {s.insert(nums[right]);while (*s.rbegin() - *s.begin() > 2){s.erase(s.find(nums[left]));left++;}ans += right - left + 1;}return ans;}
};

s.rbegin() 返回的是一个反向迭代器它指向的是容器中的最后一个元素。反向迭代器的工作方式和普通迭代器正好相反:递增反向迭代器会移动到前一个元素,递减反向迭代器会移动到后一个元素。因此,s.rbegin() 实际上给了我们一个方便的方式来访问容器中的最后一个元素

在上面这个例子中,由于multiset是一个自动排序的set容器,因此**s.begin()s.rbegin() 分别返回指向 multiset 中最小元素和最大元素的迭代器**。因为这些方法返回的是迭代器,所以我们需要使用 * 操作符来解引用迭代器,得到它们实际指向的值。

示例中erase的用法

在 C++ 的 STL 中,erase 是用来删除容器中的元素的成员函数,multiseterase 函数可以接收两种类型的参数:

  1. 一个值:erase(val) 会删除 multiset所有等于 val 的元素。
  2. 一个迭代器:erase(iterator) 会删除迭代器指向的元素

比如,在示例中,s.erase(s.find(nums[left++]))erase 函数接收的是一个迭代器。

find 函数在 multiset 中寻找给定值的元素,如果找到,返回指向这个元素的迭代器;如果没有找到,返回 s.end()。然后 s.erase 删除这个迭代器指向的元素

在示例代码中,使用迭代器而不是值作为参数,是因为我们只想删除窗口最左边的元素,而不是删除所有等于这个值的元素。如果直接使用值作为参数,s.erase(nums[left++]) 就会删除所有等于 nums[left++] 的元素。所以需要使用 find 函数找到最左边的元素的迭代器,并传递给 erase 函数。

不能写成s.erase(s.begin()+left)的原因

在使用vector容器的时候,迭代器支持随机访问的操作。例如下图:

在这里插入图片描述
但在 std::multiset 中,不能这么使用。

因为**std::multiset 中的迭代器只支持单向(forward)或双向(bidirectional)的操作,而不支持随机访问**。也就是说,不能直接加一个偏移量到 begin()。会出现下图报错。

在这里插入图片描述
如果想从 std::multisetbegin() 开始移动到某个位置,需要使用迭代器的 ++ 操作,比如:

auto it = s.begin();
std::advance(it, left);  // 或者使用 for 循环 left 次执行 ++it
s.erase(it);

以上代码中,std::advance 函数可以用于在输入迭代器上进行前进操作。但注意这个操作的复杂度是线性的,因为 std::multiset 的迭代器不支持随机访问,所以这可能会影响算法效率。

在不支持随机访问的容器内,最直接的删除元素方式

set1.erase(set1.find(a));//set中删除元素a,使用find先得到迭代器

STL中支持随机访问的迭代器

在C++的标准模板库(STL)中,std::vectorstd::dequestd::array,和std::string是支持随机访问的容器,它们的迭代器都支持随机访问

这意味着可以直接在这些容器的迭代器上加上一个偏移量来访问元素。以下是一些示例:

1. std::vector:

std::vector<int> v = {1, 2, 3, 4, 5};
auto it = v.begin() + 2;  // 现在 it 指向元素 3
v.erase(it);  // 删除元素 3

2. std::deque:

std::deque<int> d = {1, 2, 3, 4, 5};
auto it = d.begin() + 2;  // 现在 it 指向元素 3
d.erase(it);  // 删除元素 3

3. std::array:

std::array<int, 5> a = {1, 2, 3, 4, 5};
auto it = a.begin() + 2;  // 现在 it 指向元素 3
// array 不支持 erase 操作,但你可以通过迭代器访问元素

4. std::string:

std::string s = "hello";
auto it = s.begin() + 2;  // 现在 it 指向字符 'l'
s.erase(it);  // 删除字符 'l'

需要注意的是,不是所有的容器都支持随机访问。例如 std::liststd::setstd::map 等容器的迭代器只支持前向或双向访问,不能在这些迭代器上直接加上一个偏移量。同样,这些容器中的 erase 函数通常也接受一个迭代器参数,但这个迭代器不能通过加偏移量来得到

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

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

相关文章

2023年网络安全比赛--Web渗透测试国赛篇(超详细)

一、竞赛时间 180分钟 共计3小时 二、竞赛阶段 竞赛阶段 任务阶段 竞赛任务 竞赛时间 分值 1.获取Apache的版本号作为Flag值(例如:5.2.14)提交; 2.获取Samba服务器的版本号作为Flag值(例如:5.0.22)提交; 3.获取系统的内核版本号作为Flag值(例如:2.6.18)提交 4.网站根…

Redis持久化(RDB、AOF)

Redis持久化&#xff08;RDB、AOF&#xff09; 一、Redis高可用二、Redis持久化三、Redis的RDB持久化1、触发条件1.1 手动触发1.2 自动触发1.3 其它自动触发机制 2、执行流程3、启动时加载RED文件(恢复) 四、Redis的AOF持久化1、开启AOF2、执行流程2.1 命令追加&#xff08;app…

FreeRTOS_系统内核控制函数

目录 1. 系统内核控制函数预览 2. 系统内核函数详解 2.1 函数 taskYIELD() 2.2 函数 taskENTER_CRITICAL() 2.3 函数 taskEXIT_CRITICAL() 2.4 函数 taskENTER_CRITICAL_FROM_ISR() 2.5 函数 taskEXIT_CRITICAL_FROM_ISR() 2.6 函数 taskDISABLE_INTERRUPTS() 2.7 函数…

前端必备:10个有趣的 JavaScript 开发技巧,让编码更轻松

文章目录 1. 使用严格模式(strict mode)2. 遵循命名规范3. 使用模块化开发4. 使用箭头函数5. 避免全局变量6. 使用解构赋值和对象扩展7. 异步编程技巧8. 利用缓存和节流9. 使用工具库10. 不断学习和实践 当处理 JavaScript 开发时&#xff0c;以下是一些可以提高技巧的建议&…

GoLand下载、安装

一、Goland下载 官方最新版本下载地址&#xff1a; Download GoLand: A Go IDE with extended support for JavaScript, TypeScript, and databases 其他版本下载&#xff1a; Other Versions - GoLand 二、安装过程 1.下载好goland-2021.1.1安装包后&#xff0c;双击运行安装包…

【C语言督学训练营 第十六天】考研中常考的排序大题(上)---- 冒泡排序、插入排序、快速排序

文章目录 前言经典的冒泡插入排序快速排序 前言 今天要介绍的部分是排序算法&#xff0c;在很久很久之前学习过十大排序&#xff0c;当时自我感觉非常良好&#xff0c;知道今天才知道我认为的大错特错。有些排序算法会考代码题&#xff0c;有些只会考小题只需要理解思想即可&a…

四、深度学习的计算

文章目录 前言一、层和块1.1 自定义块1.2 顺序块1.3 在前向传播函数中执行代码1.4 效率问题1.5 小结 二、参数管理2.1 参数访问2.1.1 目标参数2.1.2 访问所有参数2.1.3 从嵌套块中收集参数 2.2 参数初始化2.2.1 内置初始化2.2.2 自定义初始化2.2.3 参数绑定 三、延后初始化四、…

动态规划详解Python

动态规划 动态规划&#xff08;Dynamic Programming&#xff09;是一种用于解决复杂问题的算法设计方法。它通常用于优化问题&#xff0c;其中问题可以被分解成一系列重叠子问题&#xff0c;通过存储并重复使用已经解决过的子问题的解&#xff0c;可以避免重复计算&#xff0c…

第7章 Scala集合

第7章 Scala集合 7.1 简介 ​ ​ scala.collection.immutable ​ scala.collection.mutable ​ 7.2 数组 ​ 不可变数组 package chapter07object Test01_ImmutableArray {def main(args: Array[String]): Unit {// 1. 创建数组val arr: Array[Int] new Array[Int](10…

【数据结构与算法】4、双向链表(学习 jdk 的 LinkedList 部分源码)

目录 一、双向链表二、node(int index) 根据索引找节点三、clear()四、add(int, E&#xff09;五、remove(int index)六、双向链表和单链表七、双向链表和动态数组八、jdk 官方的 LinkedList 的 clear() 方法 一、双向链表 &#x1f381; 单链表的节点中只有一个 next 指针引用…

STM32面试知识点总结分析

一、STM32F1和F4的区别&#xff1f; 内核不同&#xff1a;F1是Cortex-M3内核&#xff0c;F4是Cortex-M4内核&#xff1b; 主频不同&#xff1a;F1主频72MHz&#xff0c;F4主频168MHz&#xff1b; 浮点运算&#xff1a;F1无浮点运算单位&#xff0c;F4有&#xff1b; 功能性…

高压线路零序电流方向保护程序逻辑原理(四)

2&#xff0e;全相循环程序逻辑框图 全相循环程序逻辑简图如图3&#xff0d;18所示。程序入口首先检测标志位UQDB1&#xff0c;在采样中断服务程序中采用3U。突变量来区分接地故障和TA断线&#xff0c;接地故障时Δ3U。大于定值&#xff0c;置标志位UQDB1&#xff0c;这是11型…