【C++】STL应用(详解)

2023-05-16

  • (一)、泛型程序与STL
    • 1.泛型程序设计的基本概念
    • 2.STL简介
  • (二)、迭代器
    • 1.输入流迭代器
    • 2.输出流迭代器
  • (三)、STL应用
    • 1.撰写自己的算法和函数,结合容器和迭代器解决序列变换(如取反、平方、立方),像素变换(二值化、灰度拉伸)
      • ①序列变换(取反,平方)
      • ②像素变换
    • 2.用set存储学生信息,并进行增删改查操作
      • ①对学生信息进行增操作
      • ②对学生信息进行查操作
      • ③对学生信息进行删操作
    • 3.输入一个字符串,用map统计每个字符出现的次数并输出字符及对应的次数。

(一)、泛型程序与STL

1.泛型程序设计的基本概念

  首先先了解一下什么是泛型程序。所谓的泛型程序设计就是编写不依赖与具体数据类型的数据。C++中,模板是泛型程序设计的主要工具。泛型程序设计的主要思想是将算法从特定的数据结构中抽象出来,使算法成为通用的、可以作用于各种不同的数据结构。

2.STL简介

  标准模板库(Standard Template Library,STL)是面向对象程序设计与泛型程序设计思想相结合的一个良好典范。STL提供了一些常用的数据结构和算法。STL更大的意义在于,它定义了一套概念体系,为泛型程序设计提供了逻辑基础。
  STL所涉及的四种基本组件:容器、迭代器、函数对象、算法。
STL基本组件结构图:
在这里插入图片描述


容器(container):
①容器(container)是容纳、包含一组元素的对象。
②容器库类中包括七种基本容器:向量(vector)、双端队列(deque)、列表(list)、集合(set)、多重集合(multiset)、映射(map)、多重映射(multimap)。
③这七种容器可以分为两种基本类型:顺序容器(sequence container)和关联容器(associative container)。
④顺序容器将一组具有相同类型的元素以严格的线性形式组合起来,向量、双端队列和列表容器就属于这一种。
⑤关联容器具有根据一组索引来快速提取元素的能力,集合和映射容器就属于这一种。
⑥使用不同的容器,需要包含不同的头文件。


迭代器(iterator):
①迭代器(iterator)提供顺序访问容器中每个元素的方法。
②指针本身就是一种迭代器,迭代器是泛化的指针。
③使用独立于STL容器的迭代器,需要包含头文件iterator。
④在STL中,迭代器是算法和容器的“中间人”。


函数对象(function object):
  函数对象(function object)是泛化的函数,是一个行为类似函数的对象,可以像调用函数一样调用函数对象。任何普通的函数和任何重载了“()”运算符的类的对象都可以作为函数对象使用。使用STL的函数对象,需要包含头文件 functional。


算法(algorithm):
  STL包括七十多个算法,包括查找算法、排序算法、消除算法、计数算法、比较算法、变换算法、置换算法、容器管理等。这些算法的一个最重要的特性就是它们的统一性,并且可以广泛用于不同的对象和内置的数据类型。使用STL的算法,需要包含头文件algorithm。


(二)、迭代器

  上面初略的了解了一下什么是迭代器,现在让我们更深入地去理解应用迭代器。理解迭代器对理解STL框架并掌握STL的使用至关重要。
  Iterator(迭代器)模式又称Cursor(游标)模式,用于提供一种方法顺序访问一个聚合对象中各个元素, 而又不需暴露该对象的内部表示。或者这样说可能更容易理解:Iterator模式是运用于聚合对象的一种模式,通过运用该模式,使得我们可以在不知道对象内部表示的情况下,按照一定顺序(由iterator提供的方法)访问聚合对象中的各个元素。
迭代器的作用:能够让迭代器与算法不干扰的相互发展,最后又能无间隙的粘合起来,重载了*++==!=运算符。用以操作复杂的数据结构,容器提供迭代器,算法使用迭代器;常见的一些迭代器类型:iteratorconst_iteratorreverse_iteratorconst_reverse_iterator

1.输入流迭代器

Istream_iterator<T>(istream& in);
T是使用该迭代器从输入流中输入数据的类型。类型T要满足两个条件:
①有默认构造函数
②对该类型的数据可以使用“>>”从输入流输入。

用“++”运算符可以从输入流中读取下一个元素;若类型T是类类型或结构体,用“->”可以直接访问刚刚读取元素的成员。
Istream_iterator类模板有一个默认构造函数,用该函数构造出的迭代器指向的就是输入流的结束位置,将一个输入流与这个迭代器进行比较就可以判断输入流是否结束。

例如:

copy(istream_iterator<string>(cin),//输入流
istream_iterator<string>(), //输入流结束位置
ostream_iterator<string>(cout,"\n") //输出流及元素分隔符
);

注意:由于该程序会从标准输入流中读取数据直到输入流结束,运行该程序时,输入完数据后,在windows下需要按【ctrl+z】和回车键,在linux下需要按【ctrl+D】键,表示标准输入结束。后面凡是通过一对Istream_iterator读入数据的程序皆如此。

2.输出流迭代器

一个输出流迭代器可以用下面两个构造函数来构造:

ostream_iterator<T>(ostream&out);
ostream_iterator<T>(ostream& out,const char * delimiter);//参数delimiter是可选的,表示两个输出数据之间的分隔符

输出流迭代器也支持“++”运算符,但是该运算符实际上不会使该迭代器的状态发生任何改变,支持“++”运算仅仅是为了让它和其他迭代器有统一的接口。
适配器(adapter)是指用于为已有对象提供新的接口的对象,适配器本身一般并不提供新的功能,只为改变对象的接口为存在。输入流迭代器和输出流迭代器将输入流和输出流的接口变更为迭代器的接口,因此它们属于适配器。

(三)、STL应用

1.撰写自己的算法和函数,结合容器和迭代器解决序列变换(如取反、平方、立方),像素变换(二值化、灰度拉伸)

①序列变换(取反,平方)

代码:

#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;

//对数组中的元素取反
void transInv(int a[], int b[], int nNum) {
    for (int i = 0; i < nNum; i++)
    {
        b[i] = -a[i];
    }
}
//对数组中的元素求平方
void transSqr(int a[], int b[], int nNum)
{
    for (int i = 0; i < nNum; i++)
    {
        b[i] = a[i] * a[i];
    }
}
//对数组取反的函数模板
template < typename T>
void transInvT(T a[], T b[], int nNum)
{
    for (int i = 0; i < nNum; i++)
    {
        b[i] = -a[i];
    }
}
template < typename T>
// 返回相反数
T InvT(T a)
{
    return -a;
}
template <typename inputIter, typename outputIter, typename MyOperator>
void transInvT(inputIter begInput, inputIter endInput,
    outputIter begOutPut, MyOperator op) {
    for (; begInput != endInput; begInput++, begOutPut++)
    {
        *begOutPut = op(*begInput);
    }

}
//遍历数组的函数模板
template < typename T>
void outputCont(string strNme, ostream& os, T begin, T end)
{
    os << "数组" + strNme + "的遍历结果为:";
    for (; begin != end; begin++)
    {
        os << *begin << " ";
    }
    os << endl;
}

void Test()
{
    const int N = 5;
    int a[N] = { 1,2,4,3,5 };
    outputCont("a", cout, a, a + N);
    int b[N];
    //Vector(向量)是一个封装了动态大小数组的顺序容器(Sequence Container),
    //跟任意其它类型容器一样,它能够存放各种类型的数据。
    //可以简单的认为,向量是一个能够存放任意类型的动态数组
    vector<double> vb(N);
    vector<double> vc(N);
    //对数组中的元素取反
    transInv(a, b, N);
    outputCont("函数取反", cout, b, b + N);
    //对数组中的元素取求平方
    transSqr(a, b, N);
    outputCont("函数平方", cout, b, b + N);
    //对数组元素取反(使用模板)
    transInvT(a, b, N);
    outputCont("T模板取反", cout, b, b + N);
    //对数组元素迭代取反
    transInvT(a, a + N, vb.begin(), InvT<int>);
    outputCont("iter迭代取反", cout, vb.begin(), vb.end());

}

int main() {
    Test();
}

运行测试截图:
在这里插入图片描述

②像素变换

代码块:

template<typename T>
class MyThreshold {
public:
    //带参构造函数,后面的则是初始化,这样的初始化方式效率比较高
    MyThreshold(int n = 128) : _nThreshold(n)
    {
    }
    int operator()(T val)
    {
        return val < _nThreshold ? 0 : 1;
    }
    int _nThreshold;
};

Test():

    transInvT(a, a + N, vb.begin(), MyThreshold<int>(2));
    outputCont("像素变换", cout, vb.begin(), vb.end());

运行测试截图:
在这里插入图片描述

2.用set存储学生信息,并进行增删改查操作

  构建studentInfo类,其中有一个构造函数包含学号和姓名两个变量,还有两个对运算符的重载,一个是输出,一个是比较学号的大小以便于排序。

class studentInfo {
public:
    studentInfo(string strNo, string strName) {
        _strNo = strNo;
        _strName = strName;
    }
    string _strNo;
    string _strName;
    friend ostream& operator<<(ostream& os, const studentInfo& info)
    {
        os << info._strNo << " " << info._strName;
        return os;
    }
    friend bool operator<(const studentInfo& info1, const studentInfo& info2) {
        return info1._strNo < info2._strNo;

    }

};

  用容器vector创建一个students对象,将学生信息存储在vector当中,再通过遍历vector将其存储在set当中。

void TestSet()
{
    vector<studentInfo> students;
    students.push_back(studentInfo("10021", "Zhang san"));      // 在vector最后添加一个元素
    students.push_back(studentInfo("10002", "Li si"));
    students.push_back(studentInfo("10003", "Wang wu"));
    students.push_back(studentInfo("10011", "zhao liu"));
    students.push_back(studentInfo("10010", "sun qi"));
    set<studentInfo> studentSet(students.begin(), students.end());      // 定义studentSet为students的头部到尾部
    outputCont("student set:", cout, studentSet.begin(), studentSet.end());
 }

学生信息存储情况:
在这里插入图片描述

①对学生信息进行增操作

新增一条学生信息:学号10000,姓名JMU ljp。

    studentSet.insert(studentInfo("10000", "JMU ljp"));	//增加元素
    outputCont("增加后student set", cout, studentSet.begin(), studentSet.end());

运行结果如下:
在这里插入图片描述

②对学生信息进行查操作

查找学号:10002,姓名:Li si的学生。

    set<studentInfo>::iterator iter; 
    set<studentInfo>::iterator iter1;  // 定义迭代下标来判别是否查找成功
    iter = studentSet.find(studentInfo("10002", "Li si"));  
    cout << "查找(10002, Li si):";
    if (iter != studentSet.end())//若找到则输出学生信息
    {
        cout << "find"<<"\t";
        cout << *iter << endl;
    }
    else
    {
        cout << "can not find " << endl;
    }

运行结果如下:
在这里插入图片描述
将查找对象改为1000,Li后运行结果如下:
在这里插入图片描述

③对学生信息进行删操作

把学生Zhang san的信息删除

    studentSet.erase(studentInfo("10021", "Zhang san"));     // 删除
    outputCont("删除后的student set", cout, studentSet.begin(), studentSet.end());

运行结果如下:
在这里插入图片描述

3.输入一个字符串,用map统计每个字符出现的次数并输出字符及对应的次数。

  map是STL的一个关联容器,它提供一对一(其中第一个可以称为关键字,每个关键字只能在map中出现一次,第二个可能称为该关键字的值)的数据处理能力。

map统计字符串各个英文字母出现的次数并输出:

void TestMap(){
		string str = "linjiapeng";
	int len = str.length();
	map<char, int> _map;
	for (int i = 0; i < len; ++i)
	{
		auto ite1 = _map.find(str[i]);
		if (ite1 != _map.end())
		{
			++((*ite1).second);
		}
		else
		{
			_map.insert(pair<char, int>(str[i], 1));
		}
	}
	map<char, int>::iterator ite = _map.begin();
	for (ite; ite != _map.end(); ++ite)
	{
		cout << (*ite).first << (*ite).second << " ";
	}
}

运行结果:
在这里插入图片描述

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

【C++】STL应用(详解) 的相关文章

  • 如何从priority_queue中删除不在顶部的元素?

    在我的程序中 我需要从优先级队列中删除不在顶部的元素 可以吗 如果没有 请建议一种除了创建自己的堆之外的方法 标准priority queue
  • 如何使用类初始化 STL 向量/列表而不调用复制构造函数

    我有一个 C 程序 它使用包含类实例的 std list 如果我打电话 例如myList push back MyClass variable 它经历创建临时变量的过程 然后立即将其复制到向量 然后删除临时变量 这远没有我想要的那么高效 而
  • 在Linux上运行MFC程序

    我有一个相当大的基于 MFC 的程序 我的任务是让它在 Linux 上运行 我已经解释过 这需要将程序重新编写为带有 STL 的直接 C 更多工作 或者重新编写为 Qt C 更少工作 现在我被告知 我需要编写包装器以使每个 MFC 类在 L
  • 迭代器后继者

    我想用另一个迭代器 同类 的后继者初始化一个迭代器 任意类型 以下代码适用于随机访问迭代器 但不适用于前向或双向迭代器 Iterator i j 1 一个简单的解决方法是 Iterator i j i 但这不起作用初始化语句for 循环的
  • Microsoft 的 STL::list::sort() 使用哪种排序算法?

    注 我不小心发帖了这个问题 https stackoverflow com questions 1717773 which sorting algorithm is used by stls listsort没有指定我正在使用哪个STL实现
  • 用于列表和映射的 C++ 容器

    我们有一个键和值对的集合 我们需要一个容器 它可以帮助我们检索值 o 1 但也可以记住插入顺序 以便当我们进行迭代时 我们可以像插入顺序一样进行迭代 由于键是一个字符串 我们将无法使用集合或类似的结构 目前我们已经定义了自己的集合类 其中包
  • 如何将 std::map 输出到二进制文件?

    我怎样才能输出一个std map到二进制文件 地图声明如下所示 map
  • uninitialized_copy memcpy/memmove 优化

    我最近开始研究 MSVC 实现中的 STL 那里有一些不错的技巧 但是我不知道为什么使用以下标准 The std uninitialized copy被优化为一个简单的memcpy memmove如果满足某些条件 据我了解 输入范围可以是m
  • 从 STL 容器并行读取

    从多个并行线程读取 STL 容器是安全的 然而 表现却很糟糕 为什么 我创建了一个小对象 将一些数据存储在多重集中 这使得构造函数相当昂贵 在我的机器上大约为 5 usecs 我将数十万个小对象存储在一个大型多重集中 处理这些对象是一项独立
  • 如果键不是映射中的初始化键,STL map[key] 返回什么? [复制]

    这个问题在这里已经有答案了 这是一些示例代码 include
  • 了解 std::swap()。 tr1::_Remove_reference 的目的是什么?

    在 VS10 的 STL 实现中 有以下 std swap 变体的代码 TEMPLATE FUNCTION Move template
  • C++ STL type_traits 问题

    我正在看最新的C9讲座 http channel9 msdn com Shows Going Deep C9 Lectures Stephan T Lavavej Standard Template Library STL 10 of 10
  • 尝试将元素推入向量

    在头文件 我没有编写 中 已经定义了一个结构体 如下所示 struct MemoryMessage public boost counted base public FastAlloc explicit MemoryMessage Memo
  • 我应该使用函数还是无状态函子?

    这两段代码做同样的事情 如您所见 它将用于排序函数 哪个更好 我通常写后一种 但我看到一些程序员像以前那样做 struct val lessthan binary function
  • 当另一个进程使用 std::fstream 写入文件时从文件读取[重复]

    这个问题在这里已经有答案了 我需要从文件中逐行读取 它是由 std getline 完成的 另一个进程的问题是一直向其附加数据 然后我需要读取新行 例如 文件一开始包含10行 我的程序读取了10行 那么我的程序应该等待 过了一会儿 另一个进
  • 为什么 std::queue 使用 std::dequeue 作为底层默认容器?

    继续阅读cplusplus com http www cplusplus com reference queue queue std queue实现如下 队列被实现为容器适配器 这些类 使用特定容器类的封装对象作为其 底层容器 提供一组特定
  • 可能的 std::async 实现错误 Windows

    看来 std async 的 Windows 实现存在错误 在重负载下 大约每秒启动 1000 个异步线程 异步任务永远不会被调度 并且等待返回的 future 会导致死锁 请参阅这段代码 使用延迟启动策略而不是异步进行修改 Bundlin
  • 擦除-删除习惯用法的性能增益来自哪里

    我需要从向量中删除满足特定条件的所有元素 我的第一种方法是循环遍历向量并对满足条件的所有元素调用 vector erase 据我所理解 vector erase对于这个用例来说 性能很差 因为它从底层数组中删除了该项目 并将向量的其余部分向
  • std::map 和二叉搜索树

    我读过 std map 是使用二叉搜索树数据结构实现的 BST 是一种顺序数据结构 类似于数组中的元素 它将元素存储在 BST 节点中并按其顺序维护元素 例如如果元素小于节点 则将其存储在节点的左侧 如果元素大于节点 则将其存储在节点的右侧
  • 递增迭代器:++it 比 it++ 更高效吗? [复制]

    这个问题在这里已经有答案了 可能的重复 C 中 i 和 i 之间有性能差异吗 https stackoverflow com questions 24901 is there a performance difference between

随机推荐

  • 2023年3月计算机三级网络技术备考

    一 专项练习 网络系统结构与设计的基本原则 1 1基础知识 1 1 1 广域网技术的发展 下列关于光以太网技术特征的描述中 xff0c 错误 的是 A 能够根据用户的需求分配宽带 B 以信元为单位传输数据 C 具有保护用户和网络资源安全的认
  • Vue3项目使用 wow.js 让页面滚动更有趣~

    wow js是一个可以在页面滚动的过程中逐渐释放动画效果 xff0c 让页面滚动更有趣的一个插件库 官网 xff1a wow js Reveal Animations When Scrolling 本文就演示一下如何在Vue3项目使用 wo
  • Failed to start bean ‘documentationPluginsBootstrapper ‘; nested exception is java.lang.NullPointer

    在配置使用swagger的时候启动报错 xff0c 如下 xff1a 原因在于我在swagger配置里加上了 64 EnableSwagger2注解 xff0c 在加上它之前可以正常启动 解决方法 xff1a 在配置文件里加上 spring
  • 串口发送float类型数据

    STM32串口发送float类型数据 一 代码 1 发送 span class token keyword void span span class token function send gyro span span class toke
  • STM32 F4串口空闲中断 + DMA实现数据发送

    STM32 F4串口空闲中断 43 DMA实现数据发送 前言文章目录一 空闲中断二 DMA三 代码部分1 串口配置2 DMA配置 前言 最近在做 STM32 43 ROS车的项目 xff0c STM32与ROS之间通信由于数据量大 xff0
  • Darknet YoloV4编译+训练(避免踩坑)

    AlexAB darknet yolov4编译 43 训练 时间间隔好几天今天来更新一下yolov4的训练 训练篇 在训练之前需要对大佬的源码进行编译本本机编译 xff0c 编译过程可查看下述链接 xff1a https blog csdn
  • ubuntu下如何创建ros工作空间、创建ros功能包、创建ros节点

    1 打开终端进入存放ros工作空间的目录 xff08 比如我这里将它放在home目录下的test文件夹中 xff09 cd test 2 开始创建ros工作空间 mkdir p catkin ws src cd catkin ws src
  • STM32串口通信 (采用链表接收不定长数据帧)

    STM32串口通信 链表接收不定长数据帧 数据帧说明不太恰当的比方 数据缓冲链表结构效果展示工程文件 数据帧说明 STM32数据寄存器为USARTx gt DR寄存器 可以看到DR寄存器只有 8 0 位可以使用 xff0c 第8位用于奇偶校
  • A*寻路算法

    目录 1 动画演示2 游戏中的自动寻路A 算法3 A 寻路算法原理4 调试代码分析代码5 代码 1 动画演示 2 游戏中的自动寻路A 算法 随着3D游戏的日趋流行 在复杂的3D游戏环境中如何能使非玩家控制角色准确实现自动寻路功能成为了3D游
  • 2022数学建模国赛B题和C题高质量论文代码数据

    目录 B题论文 5 1 问题一的建模与求解 5 1 1 使用极坐标求解具体位置 C题论文 1 1 研究背景 1 2 问题的提 5 1 问题一的建模与求解 5 1 1 数据的预处理 B题论文 5 1 问题一的建模与求解 5 1 1 使用极坐标
  • stm32小白学习之寄存器名称

    IDR输入只读寄存器 xff0c ODR输出可读可写寄存器 BSRR xff08 置位寄存器 xff09 与BRR xff08 复位寄存器 xff09 CRL xff08 端口配置低位寄存器 xff09 与CRH xff08 端口配置高位寄
  • 使用Vite创建Vue3+TS项目并整合Element Plus框架等一条龙服务

    记录一下使用Vite创建Vue3 43 TS项目以及整合Element Plus框架 xff0c 还有Less Pinia Vue router monaco editor等插件或组件 一 使用Vite创建Vue3 43 TS项目 第一步
  • Qt学习 第37节:QString

    在阅读QString文档时 xff0c 出了一个词 implicit sharing copy on write xff0c 不是很懂 xff0c 下面链接解释的表明白 QT的隐式共享 Implicit Sharing 道路与梦想 CSDN
  • 下载Postman并且汉化使用

    下载Postman并且汉化使用 一 下载postman postman有不同的版本 xff0c 如果要汉化就要下载的版本与汉化包一致 下载地址 xff1a postman官网下载地址 xff1a https www postman com
  • 【Vue】postman汉化教程 保姆级教程 包教会

    下载链接 xff1a Win64 Win32 历史版本下载 请把下面链接的 34 版本号 34 替换为指定的版本号 xff0c 例如 xff1a 8 8 0 版本链接Windows32位https dl pstmn io download
  • 操作系统实验——进程与线程

    目录 1 使用GCC xff08 1 xff09 参数 xff08 2 xff09 自定义头文件 xff08 3 xff09 makefile脚本 xff08 4 xff09 gdb调试 2 进程 xff08 1 xff09 新建进程 xf
  • 串口应用(USART)

    串行口应用 1 USART介绍 通用同步异步收发器 USART 提供了一种灵活的方法与使用工业标准NRZ异步串行数据格式的 外部设备之间进行全双工数据交换 USART利用分数波特率发生器提供宽范围的波特率选择 它支持同步单向通信和半双工单线
  • cpp-httplib 避免阻塞主线程, c++封装httplib,httplib面向对象开发

    目录 说明 前言原生的httplib会阻塞你的主线程解决httplib阻塞主线程的问题BashController 面向对象风格使用httplib自定义controller MyController h文件自定义controller Tes
  • 数据结构——结构体的5种定义方式及对比

    以下仅为定义结构体的方式 xff0c 具体使用在后续的文章中介绍 span class token macro property span class token directive hash span span class token d
  • 【C++】STL应用(详解)

    一 泛型程序与STL1 泛型程序设计的基本概念2 STL简介 二 迭代器1 输入流迭代器2 输出流迭代器 三 STL应用1 撰写自己的算法和函数 xff0c 结合容器和迭代器解决序列变换 xff08 如取反 平方 立方 xff09 xff0