【C++学习五】STL库的应用

article/2025/9/30 15:20:22

文章目录

  • 初识C++之 STL标准库
    • 1. C++STL的三大核心组件
    • 2. 自定义函数与算法对容器实现操作
    • 3. 基于自定义函数以及操作模板实现简易数字图像处理
      • 3.1 图像灰度变换
      • 3.2 图像二值化
    • 4. 初识STL容器之:set集合
    • 5.初识STL容器之:map(关联容器)
    • 结语

初识C++之 STL标准库

STL 是 Standard Template Library 的缩写,中文译为“标准模板库”。STL 是 C++ 标准库的一部分。

我们之前已经基本了解了C++中的模板templet,以及模板的作用。可以说,C++STL就是一套功能强大的 C++ 模板类,提供了通用的模板类和函数,这些模板类和函数可以实现多种流行和常用的算法和数据结构,如向量、链表、队列、栈等。并且做到了数据结构和算法的分离(使用模板可以将一种算法的实现不局限于一种数据结构)。

1. C++STL的三大核心组件

C++ STL的核心主要包括以下三种组件:

  1. 容器(Containers)

    容器是用来管理某一类对象的集合。C++ 提供了各种不同类型的容器,比如 deque、list、vector、map 等。不同的容器基于不同的数据结构

  2. 算法(Algorithms)

    算法作用于容器。它们提供了执行各种操作的方式,包括对容器内容执行初始化、排序、搜索和转换等操作。以此同时,多亏了C++Templet,算法的实现也独立于容器。

  3. 迭代器(iterators)

    迭代器用于遍历对象集合的元素。这些集合可能是容器,也可能是容器的子集。

除了上面所述的STL的三大核心以外,C++STL中的算法(Algorithms)还有一个特点,那就是,算法中某一步骤的实现方式可以通过于用户外部传参(传入一个自定义的函数)实现,大大增加了算法的多样性。

2. 自定义函数与算法对容器实现操作

举一个例子,相信大家都有用过Algorithms中的sort()排序算法,sort算法的最后一个参数由用户传入比较函数,sort()算法进而根据用户自定义的比较方式进行排序。这样一来我们就可以要求sort算法按从小到大或是从大到小的方式进行排序。除此之外,假如我们传入一个类,只要我们在比较函数中定义对这个类的排序是按照类中的哪个成员按照哪种方式进行比较,sort函数就可以理解我们的意图。而不需要重复定义多个sort算法。

接下来我将定义自己的算法和函数,结合容器和迭代器解决序列变换(如取反、平方、立方),像素变换(二值化、灰度拉伸)。

自定义操作函数(可以类比于sort()):

// 对于顺序表而言的运算(使用自定义运算函数 MyOperator)
template <class T, class MyOperator>
void transCalc(T a, T& b, int nNum, MyOperator op)
{for(int i=0;i<nNum;i++){b[i] = op(a[i]);}
}// 对于链表而言的运算(使用自定义运算函数 MyOperator)
template <class inputIt, class outputIt, class MyOperator>
void transCalcT(inputIt begInput, inputIt endInput, outputIt begOutput, MyOperator op)
{for(;begInput!=endInput;begInput++,begOutput++){*begOutput = op(*begInput);}
}

自定义操作模板(可以类比于用户自定义的比较函数):

// 这里定义操作模板,可以自定义op操作:
//取反
template<class T>
T InvT(T a)
{return -a;
}
//平方
template<class T>
T SqrT(T a)
{return a*a;
}// 类操作模板,二值化:
// 由于二值化除了传入变量本身还需要传入阈值,因此使用类来定义
template<class T>
class MyThreshold
{
public:int threshold;// n默认是128MyThreshold(int n=128):threshold(n){}// 重载操作符"()",一旦使用()传入参数就执行自定义内容:int operator()(T val){return val > threshold;}
};//比较模板函数
template<class T>
bool MyCompare(T a, T b)
{return a > b;
}
//自定义比较模板类
template<class T>
class MyComp
{
public:int op;// 自定义比较MyComp(int n):op(n){}bool operator()(T a, T b){switch(op){case 0:return a == b;break;case 1:return a > b;break;case -1:return a < b;break;}}
};

打印函数,方便可视化:

// 打印函数
template <class T>
void outputCont(string strName, T beg, T end)
{cout<<strName;for(;beg!=end;beg++){cout<<*beg<<"  ";}cout<<endl;
}

测试样例:

void test_mystl()
{const int N = 5;vector<int> a = {3,5,4,1,2};vector<int> b(5);// 取反transCalc(a,b,N,InvT<int>);outputCont("Inv a:", b.begin(), b.end());// 取平方transCalc(a,b,N,SqrT<int>);outputCont("Sqr a:", b.begin(), b.end());// 二值化transCalc(a,b,N,MyThreshold<int>(2));outputCont("Sqr a:", b.begin(), b.end());// sort函数使用自定义排序方法sort(a.begin(), a.end(), MyCompare<int>);outputCont("Sort a by max:", a.begin(), a.end());// sort函数使用自定义排序类sort(a.begin(), a.end(), MyComp<int>(-1));outputCont("Sort a by min:", a.begin(), a.end());
}

测试结果:

请添加图片描述

3. 基于自定义函数以及操作模板实现简易数字图像处理

本篇博客的图像处理依赖于C++opencv开源算法包

首先定义一个操作模板函数:

// 对于图像而言的运算(使用自定义运算函数 MyOperator)
template <class MyOperator>
void transCalc(Mat &src, int w, int h, MyOperator op)
{for(int row=0;row<h;row++){for(int col=0;col<w;col++){// 图像操作src.at<uchar>(row, col) = op(src.at<uchar>(row, col));}}
}

3.1 图像灰度变换

// 类操作模板,灰度对数变换:
// 由于二值化除了传入变量本身还需要传入阈值,因此使用类来定义
template<class T>
class logTransform
{
public:int C;double Gamma;// n默认是128logTransform(int c=1, double gamma = 1.0):C(c),Gamma(gamma){}// 重载操作符"()",一旦使用()传入参数就执行自定义内容:int operator()(T val){float Val = float(val)/255;return 255*C*log(1+Val*(Gamma-1)) / log(Gamma);}
};

测试样例:

int main(int argc, char *argv[])
{// 打开灰度图像Mat img = cv::imread("C:\\Users\\S.E\\Desktop\\c++\\opencv_qt\\rice.png", 0);int w = img.cols;int h = img.rows;imshow("original", img);transCalc(img, w, h ,logTransform<uchar>(1, 0.01));imshow("gamma=0.01", img);waitKey(0);return 0;
}

测试结果:

请添加图片描述

3.2 图像二值化

// 类操作模板,二值化:
// 由于二值化除了传入变量本身还需要传入阈值,因此使用类来定义
template<class T>
class MyThreshold
{
public:int threshold;// n默认是128MyThreshold(int n=128):threshold(n){}// 重载操作符"()",一旦使用()传入参数就执行自定义内容:int operator()(T val){return (val > threshold)*255;}
};

测试样例:

int main(int argc, char *argv[])
{// 打开灰度图像Mat img = cv::imread("C:\\Users\\S.E\\Desktop\\c++\\opencv_qt\\rice.png", 0);int w = img.cols;int h = img.rows;imshow("original", img);transCalc(img, w, h ,MyThreshold<uchar>(128));imshow("Threshold=128", img);waitKey(0);return 0;}

测试结果:

请添加图片描述

4. 初识STL容器之:set集合

set是c++stl标准库实现的一个容器,能够给予数据进行自动排序。其基本的数据结构基于红黑树,因此其在插入和删除的效率上会比一般的序列容器高,比如vector

接下来我们将以set为基础实现一个非常超级无敌简易的学生管理“系统”,方便大家更好的理解。

首先定义一条学生信息的基本组成,封装成一个类:

// 学生类
class studentInfo
{
public:int _strNo;     // 学号string _strName; // 姓名// 构造函数studentInfo(int strNo, string strName){_strNo = strNo;_strName =strName;}// 重载 << 输出friend ostream& operator<<(ostream& os, const studentInfo& info){os<<endl<<info._strNo<<" "<<info._strName;return os;}// 重载比较运算符(只比较学号)friend bool operator<(const studentInfo& info1, const studentInfo& info2){return info1._strNo<info2._strNo;}
};

接着我们定义一个管理学生信息的类,用集合set存储每条学生信息,并且定义一些管理学生信息的基本增删改查方法:

值得注意的是,在对容器使用for循环遍历时可以使用auto自动声明一个迭代器。

template <class T>
class students
{
public://存储学生信息set<studentInfo> stuSet;int stuNum = 0;// 构造函数template <class t>students(t stud){for(auto it:stud){stuSet.insert(it);stuNum ++;}}// 增加一个元素void add_single(T stu){stuSet.insert(stu);stuNum ++;}// 批量增加元素template <class t>bool add_batch(t stu){for(auto it:stu){stuSet.insert(it);stuNum ++;}return true;}// 根据学号删除元素bool del(int No){for(auto it:stuSet){if(it._strNo == No){stuSet.erase(it);stuNum --;return true;}}return true;}// 根据姓名删除元素bool del(string Name){for(auto it:stuSet){if(!Name.compare(it._strName)){stuSet.erase(it);stuNum --;return true;}}return true;}// 根据学号查找姓名string searchName(int No){for(auto it:stuSet){if(it._strNo == No){return it._strName;}}return "Not Found";}// 根据姓名查找学号int searchNo(string Name){for(auto it:stuSet){if(!Name.compare(it._strName)){return it._strNo;}}return -1;}// 根据学号修改姓名void update_no(int No, string afterName){for(auto it:stuSet){if(it._strNo==No){stuSet.erase(it);break;}}stuSet.insert(studentInfo(No, afterName));}};

值得注意的是,set涉及查找并删除的实现方法中,若我们删除完set中的一条数据,应该直接return或者break退出查找的循环。这是因为在删除一条数据之后,set中的树形结构发生了改变,由于set内部的树遍历机制。导致erase 之后不能从那个起点再往回遍历,因此如果下一条数据正好在当前数据的父节点之上,往回遍历就会出现野指针的错误。即:

... ...for(auto it:stuSet){if(it._strNo==No){stuSet.erase(it);break;}}
... ...

测试样例:

void testStuSet()
{vector<studentInfo> stu1;stu1.push_back(studentInfo(11, "haotianY"));stu1.push_back(studentInfo(13, "jinyuG"));stu1.push_back(studentInfo(47, "jiawenL"));vector<studentInfo> stu2;stu2.push_back(studentInfo(41, "zhaohongH"));stu2.push_back(studentInfo(19, "chenxiS"));stu2.push_back(studentInfo(22, "yihaoW"));stu2.push_back(studentInfo(49, "haohaoW"));students<studentInfo> stuSet(stu1);// 增stuSet.add_batch(stu2);stuSet.add_single(studentInfo(22, "xiangdongX"));// 删stuSet.del(22);// 改stuSet.update_no(47, "xiuwenL");  // 根据学号修改姓名// 查cout<<stuSet.searchName(49)<<endl;      // 根据学号查找姓名cout<<stuSet.searchNo("haohaoW")<<endl; // 根据姓名查找学号outputCont("student Set:\n", stuSet.stuSet.begin(), stuSet.stuSet.end());
}

测试结果:

请添加图片描述

5.初识STL容器之:map(关联容器)

map 是一个关联容器,它提供一对一的数据处理能力(其中第一个(first)称为键,第二个(second)称为值。不同键的值可以相同),由于这个特性,它能在我们处理一对一数据的时候,在编程上提供快速通道。同时,和set一样,map内部也是自动排序的。

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

//输入一个字符串,用map统计每个字符出现的次数并输出字符及对应的次数
void countStr(string str){map<char, int> count;for(int i = 0;i<str.length();i++){// 如果第一次出现就赋值为1if(count.find(str[i])==count.end()){count[str[i]] = 1;}// 否则++else{count[str[i]]++;}}// 打印每个单词出现的次数for(auto i:count){cout<<i.first<<": "<<i.second<<"  ";}
}

测试样例:

int main()
{countStr("iuewfhjsdbfkrhedjskjloisgjipjdzzsvdfgkzlkjbhgvdvjj");return 0;
}

测试结果:

请添加图片描述

结语

本次实验基于前一次实验介绍的模板templet以及C++标准库中的STL库,实现了自定义的算法及函数并进行了简易的数字图像处理。同时,通过学生信息管理以及统计字符串中每个字母出现的次数这两个例子初步了解了set和map的基本使用方法,至此,c++对我而言算是正式敞开了遮掩的大门,露出了些许微不足道的光亮。
更多的基于C++的应用将作为我本学期的课设呈现


http://chatgpt.dhexx.cn/article/OQ2mk47C.shtml

相关文章

STL库:vector

STL库&#xff1a;vector 文章目录 STL库&#xff1a;vector1.STL库对vector的官方介绍2.vecotr的常用接口2.1 vector的构造函数2.2 vector的迭代器与遍历操作2.3 vector的容量操作2.4 vector的访问操作2.5 vector的修改操作 3.vector迭代器失效问题3.1 insert导致的迭代器失效…

深入理解STL库

关注本人公众号&#xff0c;获取更多学习资料&#xff01; 微信公众号搜索&#xff1a;阿Q正砖 上期说过C这块面试问的东西也蛮多&#xff0c;简历上只要出现C这几个字&#xff0c;那么STL库就是必问。 总不能是面试官问你了解STL库吗&#xff1f;你尴尬的说这块不怎么熟悉。…

C++ STL标准库

STL 组件 STL 是 C 标准程序库的核心。STL 内的所有组件都由模板构成&#xff0c;其元素可以是任意型别。程序员通过选用恰当的群集类别调用其成员函数和算法中的数据即可&#xff0c;但代价是 STL 晦涩难懂。 STL 组件主要包括容器&#xff0c;迭代器、算法和仿函数。 容器…

C++语法篇之STL库

1. STL介绍 STL是Standard Template Library的缩写&#xff0c;即标准模板库。之前在写 Templates 模板的时候&#xff0c;提到过STL对于模板的应用。STL是由多个模板类构成&#xff0c;能够为开发者提供通用的数据结构和算法。 STL主要包含以下内容&#xff1a; 容器 Conta…

【c++ • STL】初步认识什么是 STL 标准库

&#x1f680; 个人简介&#xff1a;CSDN「博客新星」TOP 10 &#xff0c; C/C 领域新星创作者&#x1f49f; 作 者&#xff1a;锡兰_CC ❣️&#x1f4dd; 专 栏&#xff1a;从零开始的 c 之旅&#x1f308; 若有帮助&#xff0c;还请关注➕点赞➕收藏&#xff0c;不行的…

STL库:list

STL库&#xff1a;list 文章目录 STL库&#xff1a;list1.STL库对list的官方介绍2.list的常用接口2.1 list的构造函数2.2 list的迭代器与遍历操作2.3 list的容量操作2.4 list的访问操作2.5 list的修改操作2.6 list的特别容器操作 3.list的底层源码4.list的模拟实现4.1 list的结…

STL库:string

STL库&#xff1a;string 文章目录 STL库&#xff1a;string1.STL库对于string类的介绍2.string常用接口的掌握2.1 string的构造接口2.2 string的容量操作接口2.3 string的访问操作接口2.4 string的迭代器遍历操作接口2.5 string的修改操作接口2.6 string的非成员函数重载接口2…

C++ 标准模板库STL

目录 前言 一、STL简介 二、STL的组件 三、STL头文件与命名空间 四、STL三大组件之 —— 容器 4.1 容器概述 4.2 序列式容器 4.3 排序式容器 4.4 哈希容器 五、STL三大组件之 —— 迭代器 5.1 迭代器概述 5.2 五种迭代器 5.3 迭代器的定义 5.4 迭…

C++ - STL标准库

1.C STL标准库简介 长久以来&#xff0c;软件界一直希望建立一种可重复利用的东西&#xff0c;以及一种得以制造出”可重复运用的东西” 的方法&#xff0c;从函数(functions)&#xff0c;类别(classes),函数库(function libraries),类别库(class libraries)、各种 组件&…

STL库--概述

C标准模板库&#xff08;Standard Template Library,STL&#xff09;是泛型程序设计最成功的实例。STL是一些常用数据结构和算法的模板的集合。 STL六大组件&#xff1a; 容器&#xff08;containers&#xff09;&#xff1a;存放数据 算法&#xff08;algorithms&#xff09;&…

Standard Template Library(STL,标准模板库)

Standard Template Library(STL&#xff0c;标准模板库) STL&#xff08;标准模板库&#xff09;是C标准程序库的核心&#xff0c;它深刻影响了标准程序库的整体结构。 STL是一个泛型(generic)程序库&#xff0c;提供一系列软件方案&#xff0c;利用先进&#xff0c;高效的算…

pyqt学习笔记

pyqt学习笔记 文章目录 pyqt学习笔记前言pyqt主要模块开发环境安装qtpython选择使用anaconda集成版本&#xff1a;anaconda的特点&#xff1a;安装步骤&#xff1a; pycharm导入anaconda:pycharm设置qtdesigner&#xff0c;ui转py工具: 前言 gui学习是一个比较重要的内容&…

[ PyQt入门教程 ] PyQt5开发环境搭建和配置

PyQt5工具可以快速实现简单的界面开发&#xff0c;包括界面设计、布局管理以及业务逻辑实现&#xff08;信号与槽&#xff09;。简单说就是使用PyQt5工具可以快速画一个控件摆放整齐、界面整洁有序、布局合理的界面。 课程目标 可以动手实现简单的GUI程序。系列文章主要以动手…

PyQt(QtDesigner+Python)编写程序的使用教程(简单版)

有同学问我具体怎么实现QtDesignerPython&#xff0c;简单写一下方便查看 1.安装好后Qtdesinger,打开软件&#xff0c;操作控件设计好想要的界面&#xff1b; 2.将Qtdesinger编写的.ui文件&#xff0c;使用PyUIC&#xff08;需要自己安装配置好&#xff09;软件转到.py文件 …

Python开发:PyQT安装教程

不管开发什么程序&#xff0c;一个友好的用户界面都是至关重要的&#xff0c;然而Python自身并没有集成GUI&#xff0c;但是好在自Python诞生之日起&#xff0c;就有许多优秀的GUI工具集被整合到Python当中&#xff0c;使得Python也可以在图形界面编程领域大展身手。所以从这一…

PyQt5学习教程

介绍 Qt&#xff08;官方发音 [kju:t]&#xff0c;音同 cute&#xff09;是一个跨平台的 C 开发库&#xff0c;主要用来开发图形用户界面&#xff08;Graphical User Interface&#xff0c;GUI&#xff09;程序&#xff0c;当然也可以开发不带界面的命令行&#xff08;Command…

PyQt完整入门教程 | 例程附代码

关注、星标公众号&#xff0c;直达精彩内容 来源&#xff1a;cnblogs 作者&#xff1a;lovesoo 1、GUI开发框架简介 pyqt是个好东西&#xff0c;可以做完整的测试方案、脚本、工具进行整合复用等等&#xff0c;本文将以一个实例和大家一起分享。先给自己挖个坑开个头&#xff0…

PyQt初级教程

PyQt5简介 这是一个PyQt5的入门教程.目的是帮助你使用PyQt5.本教程创建并在Linux上测试.PyQt4教程则覆盖了PyQt4,对应Python的2.x和3.x的Qt4的库. 原作地址&#xff1a;http://zetcode.com/gui/pyqt5/ 原翻译地址 &#xff1a;http://blog.csdn.net/neverstop_2009/article/c…

PyQt4入门教程(2)_PyQt4的第一个程序

注&#xff1a;文中译者的话将用方括号【】标出。 这一部分我们将学习PyQt中一些基本的函数。 一个简单的例子 这是一个能够显示出一个窗口的简单例子。目前为止我们已经可以对这个窗口干很多事情了&#xff0c;比如说改变它的尺寸&#xff0c;最大化&#xff0c;最小化………

一、PyQt基础知识

一、基础知识 &#xff08;一&#xff09;简介 1. 什么是PyQt5 PyQt是基于Digia公司强大的图形程序框架Qt的Python接口&#xff0c;由一组Python模块构成&#xff0c;它是一个创建GUI应用程序的工具包&#xff0c;由Phil Thompson开发。 自从1998年首次将Qt移植到Python上形…