C++程序设计 —— 实验四:STL 应用

目录

一、STL的基础知识

1、STL简介

2、STL基本组成

2.1 容器

2.2 迭代器

二、应用 1:结合容器和迭代器解决序列变换和像素变换

1、常规方法实现序列变换,如取反、平方、立方

2、特殊方法实现序列变换:模板函数

3、结合容器和迭代器解决序列变换

4、结合容器和迭代器解决像素变换

5、算法和函数对象的使用

(二) 应用 2:用set存储学生信息,实现增删改查操作

1、构建学生信息类StudentInfo

2、使用set容器存储学生信息

3、对学生信息进行增删改查操作

(三) 应用 3:利用map字典统计字符频数并输出

(四) 实验总结


一、STL的基础知识

1、STL简介

标准模板库(Standard Template Library,简称STL)定义了一套概念体系,为泛型程序设计提供了逻辑基础。STL中的各个类模板、函数模板的参数都是用这个体系中的概念来规定的。使用STL的模板时,类型参数既可以是C++标准库中已有的类型,也可以是自定义的类型——只要这些类型是所要求概念的模型。该库包含了诸多在计算机科学领域里所常用的基本数据结构和基本算法。

2、STL基本组成

通常认为,STL是由容器、算法、迭代器、函数对象、适配器、内存分配器这 6 部分构成,其中后面 4 部分是为前 2 部分服务的,它们各自的含义下表所示。

STL的组成含义
容器一些封装数据结构的模板类,例如 vector 向量容器、list 列表容器等。
算法STL 提供了非常多(大约 100 个)的数据结构算法,它们都被设计成一个个的模板函数,这些算法在 std 命名空间中定义,其中大部分算法都包含在头文件 <algorithm> 中,少部分位于头文件 <numeric> 中。
迭代器在C++ STL中,对容器中数据的读写,是通过迭代器完成的,扮演着容器和算法间的胶合剂。
函数对象如果一个类将 () 运算符重载为成员函数,这个类就称为函数对象类,这个类的对象就是函数对象(又称仿函数)。
适配器可以使一个类的接口(模板的参数)适配成用户指定的形式,从而让原本不能在一起工作的两个类工作在一起。值得一提的是,容器、迭代器和函数都有适配器。
内存分配器为容器类模板提供自定义的内存申请和释放功能,由于往往只有高级用户才有改变内存分配策略的需求,因此内存分配器对于一般用户来说,并不常用。
STL的基本组件及其联系


2.1 容器

STL中的容器有序列式容器关联式容器,容器适配器(stack,queue,priority queue),位集(bit_set),串包(string_package)等等。

  • 顺序容器:array(数组)、vector(向量)、deque(双端队列)、forward_list(单链表)、list(列表)
  • 有序关联容器:set(集合)、multiset(多重集合)、map(映射)、multimap(多重映射)
  • 无序关联容器:unordered_set (无序集合)、unordered_multiset(无序多重集合) 、unordered_map(无序映射)、unorder_multimap(无序多重映射)

标准容器类

特点

顺序性容器

vector

从后面快速的插入与删除,直接访问任何元素

deque

从前面或后面快速的插入与删除,直接访问任何元素

list

双链表,从任何地方快速插入与删除

关联容器

set

快速查找,不允许重复值

multiset

快速查找,允许重复值

map

一对多映射,基于关键字快速查找,不允许重复值

multimap

一对多映射,基于关键字快速查找,允许重复值

容器适配器

stack

后进先出

queue

先进先出

priority_queue

最高优先级元素总是第一个出列

序列式容器:排列次序取决于插入时机和位置
关联式容器:排列顺序取决于特定准则

容器的通用功能

  • 用默认构造函数构造空容器
  • 支持关系运算符:==、!=、<、<=、>、>=
  • begin()、end():获得容器首、尾迭代器
  • cbegin() 、cend():获取容器首、尾常迭代器,不需要改变容器时更加安全
  • clear():将容器清空
  • empty():判断容器是否为空
  • size():得到容器元素个数
  • s1.swap(s2):将s1和s2两容器内容交换
     

2.2 迭代器

迭代器是算法和容器的桥梁

  • 迭代器用作访问容器中的元素
  • 算法不直接操作容器中的数据,而是通过迭代器间接操作

算法和容器独立

  • 增加新的算法,无需影响容器的实现
  • 增加新的容器,原有的算法也能适用

迭代器的分类

  • 输入迭代器:可以用来从序列中读取数据,如输入流迭代器
  • 输出迭代器:允许向序列中写入数据,如输出流迭代器
  • 前向迭代器:既是输入迭代器又是输出迭代器,并且可以对序列进行单向的遍历
  • 双向迭代器:与前向迭代器相似,但是在两个方向上都可以对数据遍历
  • 随机访问迭代器:也是双向迭代器,但能够在序列中的任意两个位置之间进行跳转,如指针、使用vector的begin()、end()函数得到的迭代器

迭代器的区间

  • 两个迭代器表示一个区间:[p1, p2)
  • STL算法常以迭代器的区间作为输入,传递输入数据
  • 合法的区间:p1经过n次(n > 0)自增(++)操作后满足p1 == p2
  • 区间包含p1,但不包含p2

迭代器的辅助函数

  • advance(p, n):对p执行n次自增操作
  • distance(first, last):计算两个迭代器first和last的距离,即对first执行多少次“++”操作后能够使得first == last

对可逆容器的访问

STL为每个可逆容器都提供了逆向迭代器,逆向迭代器可以通过下面的成员函数得到:

  • rbegin() :指向容器尾的逆向迭代器
  • rend():指向容器首的逆向迭代器

逆向迭代器的类型名的表示方式如下(S表示容器类型):

  • S::reverse_iterator:逆向迭代器类型
  • S::const_reverse_iterator:逆向常迭代器类型

随机访问容器

随机访问容器支持对容器的元素进行随机访问

  • s[n]:获得容器s的第n个元素
  • vector和deque适用
     

二、应用 1:结合容器和迭代器解决序列变换和像素变换

1、常规方法实现序列变换,如取反、平方、立方

  对于int整型的数组,我们可以实现如下的代码:

// 序列变换 ———— 取反
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];
    }
}

// 序列变换 ———— 立方
void transCub(int a[], int b[], int nNum){
    for(int i = 0; i < nNum; i++){
        b[i] = a[i] * a[i] * a[i];
    }
}

// 模板函数:自定义输出内容
template <typename T>
void OutPutCont(string strName, ostream& os, T begin, T end){
    os<<strName<<":  ";
    for(; begin!=end; begin++){
        os<<*begin<<"\t";
    }
    os<<endl;
}

  代码测试:

int main()
{
    const int N = 5;
    int a[N] = {5, 2, 7, 0, 3};
    int b[N], c[N], d[N];
    transInv(a, b, N);         //取反
    transSqr(a, c, N);         //平方
    transCub(a, d, N);         //立方
    OutPutCont("数组a", cout, a, a + N);
    OutPutCont("取反a", cout, b, b + N);
    OutPutCont("平方a", cout, c, c + N);
    OutPutCont("立方a", cout, d, d + N);
    return 0;
}

  测试结果: 

  
 

2、特殊方法实现序列变换:模板函数

常规的方法不能代码的复用性不高,对于double型或者float型的数据,不能起到效果,所以我们可以模板函数来解决这个问题。

模板函数的相关知识可以参考我的上一章博客:C++ 程序设计 —— 实验三:模板_DreamWendy的博客-CSDN博客

// 序列变换 ———— 取反
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>
void transSqrT(T a[], T b[], int nNum){
    for(int i = 0; i < nNum; i++){
        b[i] = a[i] * a[i];
    }
}

// 序列变换 ———— 立方
template <typename T>
void transCubT(T a[], T b[], int nNum){
    for(int i = 0; i < nNum; i++){
        b[i] = a[i] * a[i] * a[i];
    }
}

  代码测试:

int main()
{
    const int N = 5;
    float a[N] = {1.5, 2.70, 1.5, 0.7, 3.1};
    float b[N], c[N], d[N];     //浮点型
    transInvT(a, b, N);         //取反
    transSqrT(a, c, N);         //平方
    transCubT(a, d, N);         //立方
    OutPutCont("数组a", cout, a, a + N);
    OutPutCont("取反a", cout, b, b + N);
    OutPutCont("平方a", cout, c, c + N);
    OutPutCont("立方a", cout, d, d + N);
    return 0;
}

  测试结果: 

  
 

3、结合容器和迭代器解决序列变换

// 结合迭代器 ———— 取反
template <typename InputIter, typename OutputIter>
void transInvT(InputIter begInput, InputIter endInput, OutputIter begOutput){
    for(; begInput != endInput; begInput++, begOutput++){
        *begOutPut = ‐ (*begInput)
    }
}

  上面代码的缺点是对于平方、立方等操作都要写重写函数实现,复用性不好,下面进行改性:

// 取反操作
template<typename T>
T InvT(T a)
{
    return -a;
}

// 平方操作
template<typename T>
T SqrT(T a)
{
    return a * a;
}

// 立方操作
template<typename T>
T CubT(T a)
{
    return a * a * a;
}

// 结合容器和迭代器解决序列变换
template <typename InputIter, typename OutputIter, typename MyOperator>
void transfrom(InputIter begInput, InputIter endInput, OutputIter begOutput, MyOperator op){
    for(; begInput != endInput; begInput++, begOutput++){
        *begOutput = op(*begInput);  // 序列变换,改写为函数的形式
    }
}

  代码测试:

int main()
{
    const int N = 5;
    int a[N] = {5, 2, 7, 1, 4}; //整型数组
    int b[N];
    vector<double> vb(N);       //vector(向量)容器

    OutPutCont("数组a", cout, a, a+N);         //输出数组a
    transfrom(a, a+N, b, InvT<int>);          //通过迭代器取反数组a
    OutPutCont("通过迭代器取反数组 a", cout, b, b + N);
    transfrom(a, a+N, vb.begin(), InvT<int>); //结合容器和迭代器取反数组a
    OutPutCont("结合容器和迭代器取反", cout, vb.begin(), vb.end());

    transfrom(a, a+N, b, SqrT<int>);          //通过迭代器平方数组a
    OutPutCont("通过迭代器平方数组 a", cout, b, b + N);
    transfrom(a, a+N, vb.begin(), SqrT<int>); //结合容器和迭代器平方数组a
    OutPutCont("结合容器和迭代器平方", cout, vb.begin(), vb.end());

    transfrom(a, a+N, b, CubT<int>);          //通过迭代器立方数组a
    OutPutCont("通过迭代器立方数组 a", cout, b, b + N);
    transfrom(a, a+N, vb.begin(), CubT<int>); //结合容器和迭代器立方数组a
    OutPutCont("结合容器和迭代器立方", cout, vb.begin(), vb.end());
    return 0;
}

  测试结果: 

  

        上述的transform算法,顺序遍历begInput和endInput两个迭代器所指向的元素;将每个元素的值作为函数对象op的参数;将op的返回值通过迭代器begOutput顺序输出;遍历完成后begOutput迭代器指向的是输出的最后一个元素的下一个位置,transform会将该迭代器返回,并存储在vector 容器中。
 

4、结合容器和迭代器解决像素变换

// 像素变换 ———— 二值化
template<typename T>
class MyThreshold{
public:
    MyThreshold(int n = 128):_nThreshold(n){}  //参数时默认为128,列表初始化成员变量
    int operator()(T val)
    {
        return val<_nThreshold ? 0 : 1;  //_nThreshold设定阈值为n,val小于阈值返回0,否则返回1
    }
    int _nThreshold;
};

// 像素变换 ———— 灰度拉伸
template<typename T>
class MyGrayTrans{
public:
    MyGrayTrans(int n = 128):nGrayTrans(n){}
    int operator()(T val){
        return val += nGrayTrans;
    }
    int nGrayTrans;
};

  代码测试:

int main()
    const int N = 5;
    int a[N] = {1, 0, 5, 2, 4};           //整型数组
    vector<double> vb(N);                 //vector(向量)容器
    OutPutCont(" 数组 a ", cout, a, a+N);   //输出数组a
    transfrom(a, a+N, vb.begin(), MyThreshold<int>(2)); //像素变换——二值化
    OutPutCont(" 二值化 ", cout, vb.begin(), vb.end());
    transfrom(a, a+N, vb.begin(), MyGrayTrans<int>(2)); //像素变换——灰度拉伸
    OutPutCont("灰度拉伸", cout, vb.begin(), vb.end());
    return 0;
}

  测试结果: 

   

把大于某个临界灰度值的像素灰度设为灰度極大值,把小于这个值的像素灰度设为灰度極小值,从而实现二值化,测试结果把阈值设为2,小于2的值变为0,大于等于2的值变为1。

5、算法和函数对象的使用

如下示例sort排序算法:对给定区间所有元素进行排序,默认为升序,也可进行降序排序。sort函数进行排序的时间复杂度为n*log2n,比冒泡之类的排序算法效率要高,sort函数包含在头文件为#include<algorithm>的c++标准库中。

语法

sort(start,end,cmp)

参数

(1)start表示要排序数组的起始地址;

(2)end表示数组结束地址的下一位;

(3)cmp用于规定排序的方法,可不填,默认升序。既可以是函数也可以是函数对象,但是必须带有具有双目运算符的比较函数即操作符(),且返回类型为bool

功能

sort函数用于C++中,对给定区间所有元素进行排序,默认为升序,也可进行降序排序。

一般是直接对数组进行排序,例如对数组a[10]排序,sort(a,a+10)。而sort函数的强大之处在可与cmp函数结合使用,即排序方法的选择。

库函数functional中定义了类greater,函数对象类greater中的定义了调用操作符(),可用作于cmp。

// 比较函数 ———— 降序
template<typename T>
bool MyComp(T a, T b){
    return a > b;
}

// 比较类
template<typename T>
class CMyComp{
public:
    bool operator()(const T& x, const T& y) const{
        return x > y;
    }
};

  测试代码:

int main(){
    const int N = 5;
    int a[N] = {1, 0, 5, 2, 4};           //整型数组a
    int b[N] = {1, 2, 3, 7, 0};           //整型数组b
    int c[N] = {0, 1, 5, 4, 0};           //整型数组c

    OutPutCont("数组 a", cout, a, a+N);    //输出数组a
    sort(a, a+N, MyComp<int>);            //调用模板函数排序
    OutPutCont("排序后", cout, a, a+N);    //输出排序后的数组a

    OutPutCont("数组 b", cout, b, b+N);    //输出数组b
    sort(b, b + N, CMyComp<int>());       //调用自定义模板类排序
    OutPutCont("排序后", cout, b, b+N);    //输出数组b

    OutPutCont("数组 c", cout, c, c+N);    //输出数组b
    sort(c, c+N, greater<int>());         //调用functional库中模板类排序
    OutPutCont("排序后", cout, c, c+N);    //输出数组b
    return 0;
}

  测试结果:

  
 

(二) 应用 2:用set存储学生信息,实现增删改查操作

set集合是c++ stl库中自带的一个容器,set具有以下两个特点:

  • set中的元素都是排好序的
  • set集合中没有重复的元素

常用操作:

begin()    返回set容器的第一个元素的地址

end()    返回set容器的最后一个元素地址

clear()     删除set容器中的所有的元素

empty()   判断set容器是否为空

max_size()   返回set容器可能包含的元素最大个数

size()    返回当前set容器中的元素个数

erase(it)        删除迭代器指针it处元素

insert()          插入某个元素

1、构建学生信息类StudentInfo

// 学生信息类
class StudentInfo{
public:
    string c_strNo;     //学号
    string c_strName;   //姓名
    StudentInfo(string strNo, string strName){  //构造函数
        c_strNo = strNo;
        c_strName = strName;
    }
    
    // 友元函数,运算符重载————输出
    friend ostream& operator<<(ostream& os, const StudentInfo& info){
        os << info.c_strNo << info.c_strName;
        return os;
    }
    
    // 友元函数,运算符重载————比较
    friend bool operator<(const StudentInfo& info1, const StudentInfo& info2){
        return info1.c_strNo<info2.c_strNo;
    }
};

2、使用set容器存储学生信息

创建类型为vector的容器students,通过push_back的方法把每一个学生信息StudentInfo加入到vector容器中,再遍历vector容器将全部的学生信息存储在set容器中,这样学生信息有序排列。

// 存储学生信息
void saveStudentInfo(){
    vector<StudentInfo> students;           //创建vector容器,存储学生信息
    students.push_back(StudentInfo("10011", "Pei Ting"));  //添加学生信息
    students.push_back(StudentInfo("10001", "Wang Yan"));
    students.push_back(StudentInfo("10051", "Zhen Hao"));
    students.push_back(StudentInfo("10037", "xin Yun"));
    students.push_back(StudentInfo("10025", "Hua Li"));

    // 创建set容器,存储学生信息
    set<StudentInfo> StudentSet(students.begin(), students.end());
    OutPutCont("Student Set", cout, StudentSet.begin(), StudentSet.end());
}

  测试结果:学生信息已经排序输出了

   

3、对学生信息进行增删改查操作

3.1 增添学生信息

//增添学生信息————插入后仍是有序排列的
StudentSet.insert(StudentInfo("10032", "Coco Bela"));

   

3.2 删除学生信息

//删除学生信息
StudentSet.erase(StudentInfo("10051", "Zhen Hao"));

   

3.3 修改学生信息

begin()返回指向容器中第一个(注意,是已排好序的第一个)元素的双向迭代器。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
end()返回指向容器最后一个元素(注意,是已排好序的最后一个)所在位置后一个位置的双向迭代器,通常和 begin() 结合使用。如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。

set类型的迭代器有const修饰符,所以不能直接修改元素,只能先删除旧的,创建新的来实现

//修改学生姓名
bool updateStuName(set<StudentInfo>& StudentSet, string strNameOld, string strNameNew){
    string strNo;        //用于保存,需要修改姓名的学生的学号
    bool result = false; //返回是修改成功
    for(auto it = StudentSet.begin(); it != StudentSet.end(); it++){
        if((*it).c_strName == strNameOld)
        {
            strNo = (*it).c_strNo;          //保存学号
            StudentSet.erase(*it);          //先删除旧的学生信息
            StudentSet.insert(StudentInfo(strNo,strNameNew));//再重新添加新的学生信息
            result = true;
            break;
        }
    }
    return result;
}

  测试代码:

updateStuName(StudentSet, "Xin Yun", "Xin Yong");      //修改学生信息
OutPutCont("Student Set:After update", cout, StudentSet.begin(), StudentSet.end());

  

3.4 查找学生信息

① set自带的find函数

find(val)在 set 容器中查找值为 val 的元素,如果成功找到,则返回指向该元素的双向迭代器;反之,则返回和 end() 方法一样的迭代器。另外,如果 set 容器用 const 限定,则该方法返回的是 const 类型的双向迭代器。
// 查找学生信息
if(StudentSet.find(StudentInfo("10001", "Wang Yan")) != StudentSet.end()){
    cout << "Find The Student! "<< endl;
}else{
    cout << "Not Find The Student! "<< endl;
}

   

  ② 自定义查找

// 按学号查找学生系信息
template <typename T>
void searStuNo(string strNo, ostream &os, T begin, T end)
{
    for(; begin !=end; begin++)
    {
        if((*begin).c_strNo == strNo)
        {
            os<<"Find The Student: "<< *begin << endl;
        }
    }
}

  

(三) 应用 3:利用map字典统计字符频数并输出

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

map是STL的一个关联容器,它提供一对一的hash。

  • 第一个可以称为关键字(key),每个关键字只能在map中出现一次;
  • 第二个可能称为该关键字的值(value);
    映射与集合同属于单重关联容器,它们的主要区别在于,集合的元素类型是键本身,而映射的元素类型是由键和附加数据所构成的二元组。
    在集合中按照键查找一个元素时,一般只是用来确定这个元素是否存在,而在映射中按照键查找一个元素时,除了能确定它的存在性外,还可以得到相应的附加数据。

// 统计字符串的字符频数
void strCounts(){
    map<char, int> strMap;   //创建字典,关键字为char类型,存储字符,键值为int类型,存储字符出现的次数
    string str;
    cout << "请输入字符串:";
    cin >> str;
    int len = str.length();
    for(int i = 0; i < len; i++){
            strMap[str[i]]++;
    }
    // 遍历输出
    for(map<char, int>::iterator it = strMap.begin(); it != strMap.end(); it++){
         cout << "字符:" <<it->first << "\t" << "频数:" << it->second << endl;
    }
}

 

(四) 实验总结

        本次实验,学习了解了STL——C++的一个标准模板库,实验过程中可以明显体会到STL 具有高可重用性。常用到的STL容器有vector、list、deque、map、set等等,它们有各自特点,如下:

  • vector: 底层数据结构为数组 ,支持快速随机访问。
  • list: 底层数据结构为双向链表,支持快速增删。
  • deque: 底层数据结构为一个中央控制器和多个缓冲区,支持首尾(中间不能)快速增删,也支持随机访问。
  • set:   底层数据结构为红黑树,有序,不重复。
  • map: 底层数据结构为红黑树,有序,不重复。

在实际使用过程中,选择哪容器,可根据以下选择:

  • 如果需要高效的随机存取,不在乎插入和删除的效率,使用vector;
  • 如果需要大量的插入和删除元素,不关心随机存取的效率,使用list;
  • 如果需要随机存取,并且关心两端数据的插入和删除效率,使用deque;
  • 如果打算存储数据字典,并且要求方便地根据key找到value,一对一的情况使用map,一对多的情况使用multimap;
  • 如果打算查找一个元素是否存在于某集合中,唯一存在的情况使用set,不唯一存在的情况使用multiset。
  • 4
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: C++的STL(Standard Template Library,标准模板库)是一个强大的库,其中包含了许多容器、算法和迭代器等组件。其中的容器是实现数据管理和存储的基本组件,包括向量、列表、队列和映射等。而在STL中使用的容器,大多采用了 C++ 的泛型编程的方式,即采用了泛型。 泛型是一种基于类型参数化的编程方式,它的主要特点是可以忽略类型细节而将通用算法应用于不同的类型数据上。在STL中,泛型的应用可以明显提高代码的复用性和灵活性,使得STL的容器可以应用于不同类型的数据。 在STL中,容器、算法和迭代器等组件都是以泛型的形式出现。泛型程序可以使用模板来定义不同类型的函数和类。例如,使用 vector 模板可以创建一个自动分配和管理内存的可变数组。使用迭代器就可以对容器中的元素进行遍历。而STL中的算法则可以对容器中的元素进行各种处理,如排序和查找等。 STL中的泛型应用使得程序员们不必为不同的数据类型写出不同的版本的代码,同时也使得算法重用更加容易。因此,STL成为了C++编程中不可或缺的一部分,它将数据结构和算法分离,使得程序变得更加简单、漂亮和容易理解。 ### 回答2: STL(标准模板库)是C++编程中的一种重要的程序库,它提供了一系列的模板类和模板函数,可以帮助开发者更加高效地进行编程。其中,泛型是STL中的重要概念,它可以实现代码的重用,提高程序的可读性和可维护性。 泛型是指在STL程序设计中,可以将容器的类型、算法的参数、迭代器的类型等抽象成具有灵活性的、可重用的模板。这种设计思想可以让程序员编写具有通用性的代码,无需为每种数据类型单独编写代码。同时,泛型还可以维护代码的一致性和可靠性,减少编程错误。 STL的泛型分为容器和算法两个方面。容器是指能够存储某种数据类型的数据结构,例如vector、list、deque、set、map等。它们的共同点是都提供了访问元素的迭代器接口,可以通过迭代器的方式对元素进行访问、添加、删除等操作。使用容器能够简化对元素的操作,提高代码的可读性。 算法是指对容器中的元素执行某些操作的函数,例如find、sort、copy等。在STL中,算法通常使用迭代器作为参数,允许程序员通过自定义函数对象来实现更灵活的算法。 STL采用有限的基本概念和范式,尝试构建一种抽象的“程序设计语言”,把现实世界中需要处理的数据组织成容器,用算法来操作容器中的数据,以及迭代器来遍历容器中的元素。这种设计使得编写代码变得简单、可读性强、可维护性好,具有很高的实用价值。 总之,STL泛型技术是C++中一个非常重要的概念,它能够提高程序的可读性和可维护性,使得程序员能够高效地开发各种应用程序。掌握STL泛型技术,不仅可以帮助程序员更好地理解C++编程,而且也可以让代码更加清晰、简洁和高效。 ### 回答3: STL(标准模板库)是C++中的一个重要组成部分,它包含很多的类模板和函数模板,而其中的泛型(generic programming)则是STL的核心理念。泛型是指在编写程序时抽象出类型,使得同一份代码适用于多种不同的数据类型,同时保持程序代码的高效和可维护性。STL采用了泛型编程的方法,利用了模板特性,实现了很多可以适用于广泛场景的标准算法和容器。以下是STL中常见的泛型及其应用。 1. 容器(Containers): STL提供了多种类型的容器,如vector、list、deque、map等等。它们都是通过模板类实现的,可以存储不同类型的数据并提供多种数据管理功能。容器可以存储基本类型或用户定义的对象,可用于解决很多实际问题。例如,vector是一种高效的数据结构,可以存储不同类型的数据,比如数组和连续的空间。list和deque是序列容器,可以方便地插入、删除和遍历数据。map是一种关联式容器,它提供了键值对的存储和查找功能,可以极大地简化一些算法。 2. 迭代器(Iterators): 迭代器是指指向容器中某个元素的指针或类似于指针的对象。迭代器可以按照顺序访问容器中的元素,并可以实现很多算法。STL中的迭代器被设计成可以与容器类型无关,使得同一份算法可以适用于不同类型的容器。例如,迭代器可以用于实现排序、搜索和复制等操作。 3. 算法(Algorithms): STL提供了很多通用算法,例如sort、find、copy等等。这些算法都是通过模板函数实现的,可以适用于不同类型的容器和迭代器。算法的实现通常采用泛型编程技术,使得代码复用率高,并且可以保证算法的高效性。 在实际应用中,STL的泛型编程理念优化了大部分的数据结构和算法的实现,并且使得代码更加清晰。STL容器除了能够存储不同类型的数据,还具有一定的自我维护机制,如动态增长、内存管理等。同时,STL也弥补了一些C++语言中的不足,如指针操作容易出错、STL提供了异常处理机制等。在实际使用中,STL容器和算法的复杂度较低,执行效率较高,因此在开发中应尽可能采用STL

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DreamWendy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值