[note] C++ STL初步(二) 迭代器、算法和映射

2023-05-16

STL算法、迭代器和映射总结

迭代器

迭代器的提出

算法函数独立于数据结构无疑是一种很好的思路,它高度体现了OOP的核心思想。

但很快,我们就会发现因各数据结构的访问形式不同,困难显而易见。比如:

int sum( vector<int> &v )	 // 对向量中的元素求和
{
	int s = 0;
	for ( int i = 0; i < v.size(); ++i )   s += v[i];
	return s;
}

int sum( List<int>& l )		// 对链表中的元素求和
{
     int s = 0;
     Link<int> *first = l.first;
	while ( first != l.last ) {		
		s += first ->elem;
		first = first ->next;
	}
	return s;
}

从而我们设想必须有一种通用的访问工具。这就是迭代器。将算法和容器隔离开的过程叫做解耦。

迭代器的分类

类型支持的操作容器举例
前向迭代器向前移动;读取;相等比较单向list
双向迭代器前向操作;向后移动双向list
随机访问迭代器双向操作;自由移动;任意读取;大小比较;相减vector

使用模型

在定义数据序列的功能上说,迭代器是一种可以表示数据序列中元素的对象。

数据序列

  1. begin()开始,end()结束
  2. 每个元素可以通过 * 进行解引用,取出对应位置的元素。
  3. 迭代器可以支持基本运算,实现在数据序列中的遍历。

常用算法

查找函数

find(begin(),end())函数,遍历查找。

find_if(begin(), end(), pred()),为查找添加条件。

谓词predicates

其中 pred() 就称为谓词。

谓词的形式:

  • 函数
  • 函数对象
bool odd(int i) return i%2;//函数形式的谓词

struct Odd
{
	bool operator(int i) const { return i%2;}
} odd;//重载括号的函数对象

if (odd(n))//两者均可用
{ ... }
vector<int>::iterator p = find_if(v.begin(), v.end, odd);
vector<int>::iterator p = find_if(v.begin(), v.end, Odd());  //创建临时函数对象

从上面的例子可以看出,在调用过程当中,二者实际上并无太大差异。

那为什么要舍近求远用函数对象呢?
思考: C++的类,相比函数,优势在于结合了结构体变量携带状态的特点。从而可以在运行时改变函数的非入口特征值。这是仅有一个入口的普通函数谓词所不能比拟的。

例如以下这个门限值的判定

template<class T>
struct Less_than 
{
	T val;   // 判定门限值
	Less_than(T& x) : val(x) { }
	bool operator()(const T& x) const { return x < val; }
};

// 在 vector<int> 查找值小于 43 的元素 
p = find_if(v.begin(), v.end(), Less_than(43)); 

//在 list<string> 查找字典序在单词 “perfection” 之前的元素
q = find_if(ls.begin(), ls.end(), Less_than("perfection")); 

函数对象的优点再论

  • 可以抽象成一类函数的判别,并可以在运行过程中改动。
  • 易于内联:现有编译器支持性好
  • STL中已有一类成熟的函数对象模板
plus<T>
minus<T>
multiplies<T>
divides<T>
modulus<T> 

multiplies<double> m;
m( x, y );

累加算法

定义在可泛化为累乘、累除、累减。

// 泛化为累乘算法
#include <numeric>//这个算法定义在numeric中
#include <functional>
void f(list<double>& ld)
{
	double product = accumulate(ld.begin(), ld.end(), 1.0, multiplies<double>());
	//...
}

内积算法

向量内积的计算方式,给出两个数据序列,第一个给出头尾,第二个给出头。结果为一个数。

// 计算加权平均成绩
#include <vector> 
#include  <numeric> >
int main()
{
    vector<double> score { 92, 77, 85,. };    // 每门课程的成绩
    vector<double> weight { 4, 2, 3,}; 	   // 每门成绩的权重

    double average =  inner_product(score.begin(), score.end(),weight.begin(), 0.0) / 
	accumulate(weight.begin(), weight.end()); 
    return;
}

内积算法也可以进行泛化。

其他常用标准库算法

算法用法
for_each(b,e,op)对区间 [b,e) 的每一个元素执行 op
r=find(b,e,v)在区间 [b,e) 查找给定值 v 的元素
r=find_if(b,e,p)在区间 [b,e) 查找符合条件 p(x) 的元素
x=count(b,e,v)在区间 [b,e) 计算值为给定值 v 的元素的个数
x=count_if(b,e,p)在区间 [b,e) 计算符合条件 p(x) 的元素的个数
r=remove(b,e,v)删除区间 [b,e) 中值为给定值 v 的元素
r=remove_if(b,e,p)删除区间 [b,e) 中符合条件 p(x) 的元素
fill(b,e,v)用给定值 v 填充区间 [b,e) 的元素
sort(b,e)对区间 [b,e) 的元素进行排序,排序条件: <
sort(b,e,p)对区间 [b,e) 的元素进行排序,排序条件: p
copy(b,e,b2)复制区间 [b,e)中的元素至另一区间(b2 起始)*dest++ = *src++;
unique_copy(b,e,b2)复制区间 [b,e)中的元素至另一区间,剔除相邻相同元素
merge(b,e,b2,e2,r)合并两个区间 [b,e), [b2,e2) 的元素至第三个区间(r 起始)
equal(b,e,b2)区间 [b,e) 与区间 [b2,b2+(e-b)) 的所有元素是否相等?

算法小结

  • 面向一个或更多的序列进行处理
    • 通常通过一对迭代器定义序列的范围
  • 支持一个或多个类型的操作
    • 利用函数对象定义操作类型
    • 利用普通函数定义操作类型
  • 一般通过返回指向序列尾部的迭代器报告“错误或操作失败”

关联容器与映射

  • map是仅次于 vector 的STL容器。
  • 基于平衡二叉树实现
  • 支持通过下标访问元素

映射的常见操作

标准操作:begin(), end(), size(), empty(), clear()
插入操作:

age.insert( pair<string,int>{ “Andy”, 10 } );  // 插入1 个键值对(“Andy”, 102)
age.insert( make_pair(“Andy”, 10 ) ) ; // 利用 make_pair() 函数插入

下标操作:

int n = age.[“Jack”]; 	// 若键值 “Jack” 存在,返回年龄值 
//否则,将键值对 (“Jack”, int{}) 插入 age,返回 int{} 
age[“Andy”] = 12; // 若键值 “Andy” 存在,改变年龄值为 12      
// 否则将键值对 ( “Andy”, int{12} ) 插入age,返回 int{12}

删除操作:

age.erase(“Andy”); 	// 删除键值为 “Andy” 的元素

查找操作:map的查找非常高效

map<string,int>::iterator it = age.find(“Andy”);   // 查找指定键值的元素
if( it != age.end() ) cout<<it->first<<it->second<<endl;   //找到,打印输出

集合set

去除了映射中的值维,无下标操作。键不重复,同样利用平衡二叉树高度有序。

利用set实现字典

int main()
{
   // 利用输入流初始化 set
   set<string> words{ istream_iterator<string>{ cin },
                                    istream_iterator<string>{ } } );
   
   // 利用拷贝算法将 set 中的元素输出至输出流
   copy( words.begin(), words.end(),
             ostream_iterator<string>{cout, "\n"} ); 
}

字典如果使用vector实现,则需要先读入,后排序,再 unique_copy。使用set极大减少了因顺序和判断重复造成的开销。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[note] C++ STL初步(二) 迭代器、算法和映射 的相关文章

随机推荐

  • NRF24L01几个函数的分析

    首先看两个版本关于NRF的宏定义 xff1a 开发板 xff1a 遥控器 xff1a 1 xff0c 最基本的读写函数 xff0c 函数的返回值就是读来的数据 xff0c 形参就是写入的数据 stm32mini开发板例程中 xff1a sp
  • stm32f103之HC_SR04超声波测距

    参考资料 xff1a stm32与HC SR04超声波传感器测距 HC SR04超声波测距注意事项 STM32 驱动HC SR04超声波测距模块 HC SR04初识 HC SR04 超声波原理图讲解与时序分析与arduino使用 HC SR
  • stm32之蓝牙模块HC-05使用

    参考资料 xff1a 常用模块 HC 05蓝牙串口通信模块使用详解 xff08 实例 xff1a 手机蓝牙控制STM32单片机 xff09 HC 05蓝牙模块使用教程 HC 05蓝牙模块使用记录 补充与理解 xff1a 套餐有两个板子 一个
  • MPU9250的MPL移植_HAL库(以STM32F103为主控)

    准备材料 xff1a 驱动库 xff1a motion driver 6 12 硬件 xff1a 正点原子MINI STM32f103RCT6硬件IIC PB8 PB9 GY 91模块 看图可知AD0接地 xff0c 地址是0X68 硬件连
  • MPU9250简单快速更改MPL驱动,方便使用MPL和DMP

    附件准备材料 xff1a 我自己的资料MPU9250 c和MPU9250 h 1 xff0c 使用stm32cubemx配置好IIC 2 xff0c 在c c 43 43 处加入宏定义MPU9250 EMPL 最后为 xff1a USE H
  • 重定向printf,不使用微库,采用ARM Compiler 6 报错如何解决?

    复制正点原子的以下代码 xff0c 不使用微库 xff0c 采用ARM Compiler 6 报错 xff1a 报错 xff1a pragma import is an ARM Compiler 5 extension and is not
  • uint8_t / uint16_t / uint32_t /uint64_t 这些数据类型是什么?

    uint8 t uint16 t uint32 t uint64 t 都是别名 xff0c c语言中有哪些数据类型 xff1f 怎么样取别名 在C语言中有6种基本数据类型 xff1a short int long float double
  • 使用stm32c8t6和mpu6050制作一台穿越机

    飞控部分 xff1a 介绍 xff1a 使用stm32c8t6和mpu6050制作一款低价飞控 xff0c 固件用的是开源的betaflight 3 2 5 NAZE xff0c 飞行噪声很小 xff0c 可能是桨叶好 xff0c 乾丰5寸
  • 小米平衡车plus放久后无法充电解决办法

    半年没在家 xff0c 电池没充电 xff0c 回来后发现已经无法充电 xff0c 看了网上一些 激活神器 的产品 xff0c 有人说是智商税 xff0c 我猜那个东西也没什么神奇的东西 xff0c 像这款plus的充电线上3孔的 xff0
  • c语言宏函数怎么传递宏参数_C语言中的宏参数评估

    c语言宏函数怎么传递宏参数 We can define a function like Macro in which we can pass the arguments When a Macro is called the Macro bo
  • MiniFly V1.1开源四轴驱动代码分析八:旋转矩阵、控制分配矩阵等分析介绍

    很久没更新 看见订阅数量持续增加 感觉得加点料才对得起大家的 旋转矩阵 前言 在网上搜索到的一下关于旋转矩阵的表达形式 看起来很像 都是三角函数组合成 不同资料的正负号或者字母不一样 甚至一些是有模有样的复制粘贴 看的脑壳疼 旋转矩阵的形式
  • 数据区、栈区、堆区、代码区

    简介 1 栈区 stack xff1a 由系统的编译器自动的释放 xff0c 主要用来存放方法中的参数 xff0c 一些临时的局部变量等 xff0c 并且方法中的参数一般在操作完后 xff0c 会由编译器自动的释放掉 2 堆区 heap 由
  • 上位机PC控制UR3机器人实现方式

    一 在计算机上安装urx 库 终端输入 xff1a pip install urx xff1b 参考和例程下载见 xff1a https github com SintefManufacturing python urx xff1b 二 利
  • STM32实战项目-串口打印

    前言 xff1a 本小结主要实现串口打印功能 xff0c 主要将上一结的状态机运行次数 xff0c 通过串口在串口终端上打印出来 xff0c 硬件电路上主要是TTL转USB驱动电路 xff0c 软件上主要有状态机函数 xff0c 串口发送函
  • CURL详解

    原文链接 xff1a https www cnblogs com xishaonian p 6550613 html span class token number 1 span CURL详解 span class token number
  • STM32F103C8T6串口通信

    STMF103C8T6串口通信 串口相关的固件函数 xff1a mainusart cusart h 串口作为 MCU 的重要外部接口 xff0c 同时也是软件开发重要的调试手段 xff0c 其重要性不言而喻 关于STM32F103C8T6
  • 单片机(中断系统-串口通信)

    1 RETI 中断操作指令 这条指令的功能和RET指令相似 xff0c 2条指令的不同之处是 xff1a 本指令清除了中断响应时 xff0c 被置1的MCS 51内部不可寻址的 优先级生效 触发器清零 中断程序完成后 xff0c 一定要执行
  • ESP32 for arduino 的3个hardware serial

    在arduino IDE的开发环境中 xff0c 如果使用的开发板不是arduino的开发平台 xff0c 而是ESP32模组的开发板 xff0c 那么在实际开发中由于ESP32的支持库与arduino不同 xff0c 会使得我们在使用一些
  • 大疆开发板A型基于HAL库驱动M3508直流无刷电机及PID控制

    1 首先 xff0c 我们先了解一下大疆开发板A型的资料 xff0c 官方有提供 官网 xff1a RoboMaster 机甲大师赛 芯片型号STM32F427IIH6 2 了解M3508直流无刷电机的资料 xff0c 官网有提供 3 于是
  • [note] C++ STL初步(二) 迭代器、算法和映射

    STL算法 迭代器和映射总结 迭代器 迭代器的提出 算法函数独立于数据结构无疑是一种很好的思路 xff0c 它高度体现了OOP的核心思想 但很快 xff0c 我们就会发现因各数据结构的访问形式不同 xff0c 困难显而易见 比如 xff1a