文章目录

  • 初识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++的应用将作为我本学期的课设呈现

【C++学习五】STL库的应用相关推荐

  1. robot framework学习五——AutoltLibrary库

    安装中遇到的问题: 安装好了AutoItLibrary,但是导入到RIDE后,仍然红色显示 搜索了下解决办法,说要安装下autoit-v3-setup.exe https://www.autoitsc ...

  2. 《C++标准库》学习笔记 — STL —流

    <C++标准库>学习笔记 - STL -流 一.操控器 1.原理 2.自定义操控器 3.控制输入的宽度 二.自定义 I/O 操作符 1.重载输出操作符 2.输入操作符 三.自定义格式化标志 ...

  3. c++ stl库的基础学习

    stl库学习 学了之后发现,太棒了,终于可以像python一样,不用那么麻烦了 这里面的东西其实都是可以类比到python那里面的 比如vector就是list,map就是dict,set就是会知道排 ...

  4. 目前最好用的大规模强化学习算法训练库是什么?

    点击蓝字  关注我们 本文整理自知乎问答,仅用于学术分享,著作权归作者所有.如有侵权,请联系后台作删文处理. 本文精选知乎问题"目前最好用的大规模强化学习算法训练库是什么?"评论区 ...

  5. [c++]巧用stl库-啤酒与尿布

    [c++]<-巧用stl库-> 啤酒与尿布 前言 大家好,楼主计算机专业大学狗一枚.<啤酒与尿布>是专业课的一道课后习题,觉得我个人思路比较新颖,在此分享.能力一般,水平有限, ...

  6. 例题5-3安迪的第一个字典 UVa10815--C++STL库映射set的应用

    前言 不定期更新C++的STL库以及算法练习的笔记 分享给大家 也是督促自己不断努力学习算法与程序设计 学习算法之前,要想高效简洁的写好代码,还需要熟练掌握STL库的一些方法和数据结构 参考书籍: & ...

  7. 强化学习环境全库安装(从mujoco到spinningup)

    强化学习环境全库安装 从mujoco200到spinningup (上篇) 前言 一: 安装Mujoco200物理引擎 二. 创建conda虚拟环境 1:选择python版本 2.创建conda虚拟环 ...

  8. STL库:map和set

    STL库:map和set 文章目录 STL库:map和set 1.STL库中set的官方介绍 2.set的常用接口 3.set的总结 4.STL库中multiset的官方介绍 5.STL库中map的官 ...

  9. C++STL库:String介绍

    C++STL库 学习方法:使用STL的三个境界:能用,明理,能扩展. 今天我们开启一个新主题:C++数据结构之STL库,我们将介绍STL库里常用库的用法与实现过程. 常用库 库名称 所需头文件 数据结 ...

  10. Qt框架与STL库之间的巅峰对决:差异、优缺点及适用场景

    Qt框架与STL库之间的巅峰对决:差异.优缺点及适用场景 引言 对比的重要性 Qt框架与STL库简介 博客内容概览 Qt框架基础 Qt框架的特点与组成 Qt的信号槽机制 Qt容器类简介 数据结构的对比 ...

最新文章

  1. envoy实现_网络通信与治理,谁更在行?Envoy 和 Nginx 对比 | 本月送书活动来啦
  2. 懒人神器 !一个创意十足的 Python 命令行工具
  3. 把内存虚拟成硬盘给代码加速
  4. QTP的那些事--QTP回放iFrame控件时间非常慢的问题分析
  5. 我国数字出版发展尚存三大难题
  6. 为什么要用相对论为GPS导航提供修正
  7. 如何让ASP.NET默认的资源编程方式支持非.ResX资源存储
  8. python实现程序重启_如何让python程序重新启动到某一行?
  9. 设计模式学习系列9 外观模式Facade
  10. 怎么做一个定时消息提醒_如何用Nodejs编写一个定时消息提醒应用?
  11. staruml 为类的属性指定数据类型_关于python的数据类型
  12. SpringSecurity实战(四)-集成图片验证码-过滤器方式实现
  13. java实现手机尾号评分
  14. 3dmax如何进行网络渲染?网渲云渲染渲染农场怎么用?
  15. linux 程序被Killed,查看原因
  16. 姨的包养,有质量,无 Bug !
  17. Java开源JEE框架
  18. 洗车店开发小程序都有哪些功能
  19. 改编的一个屏幕保护程序
  20. 华为c语言机试题库及答案,华为C语言机试题面试题汇总.doc

热门文章

  1. clickhouse各种表引擎的异同
  2. js 分页页码 根据总条数计算有多少页,计算页码
  3. 1 Spark机器学习 spark MLlib 入门
  4. 利用BioEdit做多序列一致性比对
  5. 微软内置真正linux_如何使用Microsoft Word的内置屏幕截图工具
  6. python数据清洗入门教程(完整版)
  7. 拼多多API接口调用方法(内附上多个可用API)
  8. Spring学习-入门
  9. python自动化测试工程师面试题(转载师傅:上海悠悠)
  10. oracle中on和where的区别,Oracle里面的外连中where和on之后and有啥区别