文章目录
【C++实战四】STL初体验
1. STL的基本概念和组成
基本概念:STL全称是Standard template library,也叫做标准模板库,其中包含有大量的模板类和模板函数。也可以说STL 是一些容器、算法和其他一些组件的集合。
三大核心组件:容器、算法、迭代器
组成 | 含义 |
---|---|
容器 | 一些封装数据结构的模板类,例如vector,list等 |
算法 | 一些被设计成模板函数的数据结构算法 |
迭代器 | 实现对容器数据的读和写,扮演着容器和算法之间的胶合剂 |
2. 自定义函数实现序列变换
序列变化是我们经常会遇到的,且我们经常结合容器实现序列变化,例如取反,平方,立方等操作。并采用迭代器进行容器数据的读写。
定义序列容器的操作模板:
// 定义模板实现容器的批量操作,其中MyOperator实现单元素的操作
template <class T, class MyOperator>
void Batch_op(T a, T& b, int Num, MyOperator op)
{
for(int i=0;i<Num;i++)
{
b[i] = op(a[i]);
}
}
定义不同序列变换操作模板:
// 取反操作
template<class T>
T InvT(T a)
{
return -a;
}
// 平方操作
template<class T>
T Sqrt(T a)
{
return a * a;
}
// 立方操作
template<class T>
T Cube(T a)
{
return a * a * a;
}
测试函数:
void test()
{
// 初始化向量
vector<int> a{1,2,3,4,5,6,7,8,9,10};
vector<int> b(10);
// 初始化迭代器用于容器的读取
vector<int>::iterator i;
// 取反输出
cout << "序列取反输出:";
Batch_op(a,b,10,InvT<int>);
for(i = b.begin();i != b.end(); i++)
cout << *i << " ";
cout << endl;
// 平方输出
cout << "序列平方输出:";
Batch_op(a,b,10,Sqrt<int>);
for(i = b.begin();i != b.end(); i++)
cout << *i << " ";
cout << endl;
// 立方输出
cout << "序列立方输出:";
Batch_op(a,b,10,Cube<int>);
for(i = b.begin();i != b.end(); i++)
cout << *i << " ";
}
运行结果:
序列取反输出:-1 -2 -3 -4 -5 -6 -7 -8 -9 -10
序列平方输出:1 4 9 16 25 36 49 64 81 100
序列立方输出:1 8 27 64 125 216 343 512 729 1000
3. 自定义函数实现像素变换
定义图像的操作模板:
// 定义图像操作模板
template <class MyOperator>
void batch_pix(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));
}
}
}
定义不同像素变换操作模板:
// 对数变换
template<class T>
class logTransform
{
public:
int C;
double Gamma;
logTransform(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);
}
};
// 图像二值化
template<class T>
class MyThreshold
{
public:
int threshold;
MyThreshold(int n=128):threshold(n){}
// 重载操作符
int operator()(T val)
{
//大于阈值*255
return (val > threshold)*255;
}
};
测试代码:
using namespace std;
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <set>
using namespace cv;
int main(){
// 读取图像
Mat img=imread("D:\\desktop\\1.png",0);
// 读取图像宽高
int w = img.cols;
int h = img.rows;
// 显示原始图像
imshow("original", img);
// 显示二值图像
batch_pix(img, w, h ,MyThreshold<uchar>(128));
imshow("erzhi", img);
// 灰度变换操作
//batch_pix(img, w, h ,logTransform<uchar>(1, 100));
//imshow("gamma=100", img);
waitKey(0);
return 0;
}
二值化结果:
对数变换结果:
4. 通过set集合实现简单的学生管理系统
set容器的常用操作:
函数 | 作用 |
---|---|
s.size( ) | 返回容器中的元素个数 |
s.begin( ) | 返回容器中的第一个元素 |
s.end( ) | 返回容器中的最后一个元素 |
s.clear( ) | 清空容器中的所有元素 |
s.empty( ) | 判断容器是否为空 |
s.insert( ) | 插入一个元素 |
s.erase( ) | 删除一个元素 |
学生类的构建:
// 包括构造函数和运算符重载
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;
os << endl;
return os;
}
//比较学号大小
friend bool operator < (const studentInfo& info1, const studentInfo& info2) {
return info1._strNo < info2._strNo;
}
};
测试函数:
void TestSet()
{
vector<studentInfo> students;
// 插入学生对象信息(动态push)
students.push_back(studentInfo("10021", "Zhaohong Huang"));
students.push_back(studentInfo("10002", "Haotian Yan"));
students.push_back(studentInfo("10003", "Jiawen Liu"));
students.push_back(studentInfo("10011", "Xinyu Hu"));
students.push_back(studentInfo("10010", "Tao Zi"));
// 建立set容器
set<studentInfo> studentSet(students.begin(), students.end());
// 初始化迭代器
set<studentInfo>::iterator i;
//遍历学生信息(自动排序)
for(i = studentSet.begin();i != studentSet.end(); i++)
cout << *i << " ";
cout << "-----------" << endl;
//删除指定学号
studentSet.erase(studentInfo("10021", "Zhang san"));
for(i = studentSet.begin();i != studentSet.end(); i++)
cout << *i << " ";
cout << "-----------" << endl;
//查询指定学号的学生姓名
const char* num = "10002";
for (i = studentSet.begin(); i != studentSet.end(); i++)
{
if (((*i)._strNo).compare(num) == 0)
cout <<"该学号对应的学生姓名为:"<< (*i)._strName << " ";
}
}
运行结果:
10002: Haotian Yan
10003: Jiawen Liu
10010: Tao Zi
10011: Xinyu Hu
10021: Zhaohong Huang
-----------
10002: Haotian Yan
10003: Jiawen Liu
10010: Tao Zi
10011: Xinyu Hu
-----------
该学号对应的学生姓名为:Haotian Yan
5. 通过map关联容器实现字符统计
map是STL的一个关联容器,它提供一对一的服务(有点类似python中的字典)。其中第一个称为关键字(仅出现一次),第二个称为关键字的值。且map内部自建一颗红黑树,这棵树具有对数据进行自动排序的功能。
void TestMap()
{
// 初始化map,可见一对一(关键字是char型的,关键字的值是int型的)
map<char, int> word_count;
const char* word = "JMU-HZH";
// 对关键字的值进行赋值
for (int i = 0; i < strlen(word); i++)
{
++word_count[word[i]];
}
// 初始化map的迭代器
map<char, int>::iterator iter;
// 计数输出
for (iter = word_count.begin(); iter != word_count.end(); iter++)
{
cout << "[" << iter->first << "]的个数 = " << iter->second << endl;
}
}
运行结果:
[-]的个数 = 1
[H]的个数 = 2
[J]的个数 = 1
[M]的个数 = 1
[U]的个数 = 1
[Z]的个数 = 1
6. 总结
本篇博客实现了一些STL的简单应用,并结合了opencv等相关内容。首先,STL是C++代码编写中一个很好的工具,它可以提高编码效率,且可以丰富代码的灵活性;同时,STL的应用充分结合了之前学习的函数重载,函数模板,虚函数等内容,说明一个完整的C++工程需要灵活且丰富的知识联动性。