【C++实战四】STL初体验

【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++工程需要灵活且丰富的知识联动性。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值