C++(四):stl应用

1. 前言

stl标准模板库,提供一些常用得数据结构和算法。STL定义了一套概念体系,为范型程序设计提供了逻辑基础。

2. STL基本组件

以下是STL所涉及的四种基本组件。

2.1 容器

容器是容纳、包含一组元素的对象。 分为顺序容器和关联容器两种基本类型。
在这里插入图片描述

2.1.1 顺序容器

array(数组)、vector(向量)、deque(双端队列)、forward_list(单链表)、list(列表)
以上这些在逻辑上可以看作长度可扩展的数组
由于元素线性排列,所以可以随时在指定位置插入元素和删除元素

  • 但必须符合Assignable这一概念,也就是具有公有的复制构造函数并且可以用“=”赋值
  • 以上那些顺序容器中array对象的大小固定,forward_list有特殊的添加和删除操作

2.1.2(有序)关联容器

有序容器中键(key)按顺序存储

  • set(集合)、multiset(多重集合)、map(映射)、multimap(多重映射)

代码:

void TestMap(){
    map<string,int> stu;
    stu["01"] = 100;
    stu["10"] = 99;
    stu["03"] = 98;
    stu["10"] = 80;//由于map不具有覆盖功能所以输出时,10号学生的成绩为99
    for(map<string,int>::iterator it = stu.begin();it!=stu.end();it++){
        cout<<it->first<<" "<<it->second<<endl;
    }
}

void TestSet(){
    vector<studentInfo> students;
    students.push_back(studentInfo("10021","Zheng jiawen"));
    students.push_back(studentInfo("10002","Li si"));
    students.push_back(studentInfo("10003","Wang wu"));
    students.push_back(studentInfo("100011","Li yue"));
    students.push_back(studentInfo("10010","Wu si"));
    set<studentInfo> studentSet(students.begin(),students.end());
    outputCont("student set",cout,studentSet.begin(),studentSet.end());

}

结果:

01 100
03 98

2.1.3 无序关联容器

无序容器按照哈希函数组织元素

  • unordered_set(无序集合)、unordered_multiset(无序多重集合)
  • unordered_map(无序映射)、unordered_multimap(无序多重映射)

2.1.4 通用功能

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

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

代码:

outputCont("vb",cout,vb.begin(),vb.end());
outputCont("vc",cout,vc.begin(),vc.end());
vb.swap(vc);
outputCont("vb swaped",cout,vb.begin(),vb.end());

结果:

vb:0	1	1	1	1	
vc:0	0	0	0	0	
vb swaped:0	0	0	0	0

2.1.5 对可逆容器的访问

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

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

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

  • S::reverse_ iterator: 逆向迭代器类型
  • S: :const_ reverse_ iterator:逆向常迭代器类型

2.1.6 随机访问容器

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

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

2.2 迭代器

迭代器式算法个容器的桥梁

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

算法和容器是独立的

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

2.2.1 迭代器的操作

  1. 迭代器是泛化的指针,提供了类似指针的操作
  2. 输入迭代器:可以用来从序列中读取数据
  3. 输出迭代器:允许向序列中写入数据
  4. 前向迭代器:既是输入迭代器又是输出迭代器,并且可以对序列进行单向的遍历
  5. 双向迭代器:与前向迭代器相似,但可以在两个方向上都可以对数组遍历
  6. 随机访问迭代器:也是双向迭代器,但能够在序列中的任意两个位置之间进行跳转

2.2.2 迭代器的区间

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

2.3 函数对象

函数对象是一个行为类似函数的对象,对它可以像调用函数一样调用。函数对象是泛化函数

2.4 算法

使用STL的算法需要包含头文件<algorithm>
如下所示,是transfrom算法的示例

template <typename inputIter,typename outputIter,typename MyOperator>
void transInvT(inputIter begInput,inputIter endInput,
               outputIter begOutPut,MyOperator op){
    for(;begInput!=endInput;begInput++,begOutPut++){
        //*begOutPut = -(begInput);
        *begOutPut = op(*begInput);//op:一个函数,说明了具体实现的操作,实现通用
    }
}

transInvT(a,b,nNum);
outputCont("InvT a T",cout,b,b+nNum);

输出

InvT a T:-1	-2	-3	-6	-4	

3.映射(map)

映射与集合同属于单重关联容器,主要区别在于集合的元素类型是键本身,而映射的元素类型是由键和附加数据所构成的二元组。

-有key和value,按照value来排序

  • 在集合中按照键查找一个元素时,一般只是用来确定这个元素是否存在,而在映射中按照键查找一个元素时,除了能确定它的存在我外,还可以得到相应的附加数据。

代码:

//map不具有覆盖功能
void TestMap(){
    map<string,int> stu;
    stu["01"] = 100;
    stu["10"] = 99;
    stu["03"] = 98;
    stu["10"] = 80;//由于map不具有覆盖功能所以输出时,10号学生的成绩为99
    for(map<string,int>::iterator it = stu.begin();it!=stu.end();it++){
        cout<<it->first<<" "<<it->second<<endl;
    }
}

结果:

01 100
03 98
10 80

4.集合(set)

集合用来存储一组无重复的元素。由于集合的元素本身是有序的,可以高效查找指定元素,也可以方便地得到指定大小范围地元素在容器中所处的区间。
用平衡二叉树存储。

  • key和value一样

代码:

void TestSet(){
    vector<studentInfo> students;
    //添加相关信息
    students.push_back(studentInfo("10021","Zheng jiawen"));
    students.push_back(studentInfo("10002","Li si"));
    students.push_back(studentInfo("10003","Wang wu"));
    students.push_back(studentInfo("100011","Li yue"));
    students.push_back(studentInfo("10010","Wu si"));
    set<studentInfo> studentSet(students.begin(),students.end());
    outputCont("student set",cout,studentSet.begin(),studentSet.end());

}

结果:

student set:100011 Li yue
	10002 Li si
	10003 Wang wu
	10010 Wu si
	10021 Zheng jiawen

5. 代码

#include "stl.h"
#include <vector>
#include <map>
#include <iostream>
#include <algorithm>//算法库
#include <functional>
#include <set>

using namespace std;
stl::stl(){

}

//取负
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];
    }
}

//加入模板的取负
template <typename T>
void transInvT(T a[],T b[],int nNum){
    for(int i = 0;i<nNum;i++){
        b[i] = -a[i];
    }
}

//定义的moperator函数
template <typename T>
T InvT(T a){
    return -a;
}

//二值化的阈值
template <typename T>
class MyThreshold{
public:
    MyThreshold(int n = 128):_nThreshold(n){};//初始化
    int operator()(T val){//用模板来表示传入的值得类型
        return val<_nThreshold?0:1;
    }
    int _nThreshold;
};

//完成对所有的容器进行操作并保存在另一个容器中
//模板,输入输出
template <typename inputIter,typename outputIter,typename MyOperator>
void transInvT(inputIter begInput,inputIter endInput,
               outputIter begOutPut,MyOperator op){
    for(;begInput!=endInput;begInput++,begOutPut++){
        //*begOutPut = -(begInput);
        *begOutPut = op(*begInput);//op:一个函数,说明了具体实现的操作,实现通用
    }
}

//输出函数的重载
template <typename T>
void outputCont(string strName,ostream& os, T begin, T end){
    os<<strName<<":";
    //遍历输出
    for(;begin!=end;begin++){

        os<<*begin<<"\t";
    }
    os<<endl;
}

//降序排列
template <typename T>
bool mycomp(T a,T b){
    return a>b;
}

//比较函数
template <typename T>
class MyCompC{
public:

    bool operator()(const T& x,const T& y) const{
        return x>y;
    }
};

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<<'\n';
        return os;
    }
    friend bool operator < (const studentInfo& info1,const studentInfo& info2){
        return info1._strNo < info2._strNo;
    }
};

void TestSet(){
    vector<studentInfo> students;
    students.push_back(studentInfo("10021","Zheng jiawen"));
    students.push_back(studentInfo("10002","Li si"));
    students.push_back(studentInfo("10003","Wang wu"));
    students.push_back(studentInfo("100011","Li yue"));
    students.push_back(studentInfo("10010","Wu si"));
    set<studentInfo> studentSet(students.begin(),students.end());
    outputCont("student set",cout,studentSet.begin(),studentSet.end());

}

//map不具有覆盖功能
void TestMap(){
    map<string,int> stu;
    stu["01"] = 100;
    stu["10"] = 99;
    stu["03"] = 98;
    stu["10"] = 80;//由于map不具有覆盖功能所以输出时,10号学生的成绩为99
    for(map<string,int>::iterator it = stu.begin();it!=stu.end();it++){
        cout<<it->first<<" "<<it->second<<endl;
    }
}


void TestVector(){
    vector<studentInfo> students;
    students.push_back(studentInfo("10021","Zheng jiawen"));
    students.push_back(studentInfo("10002","Li si"));
    students.push_back(studentInfo("10003","Wang wu"));
    students.push_back(studentInfo("100011","Li yue"));
    students.push_back(studentInfo("10010","Wu si"));
    vector<studentInfo>::iterator it = students.begin();
    advance(it,2);//从第二个开始排列
    sort(it,students.end());
    outputCont("students sorted",cout,students.begin(),students.end());

    students[2]._strName = "jwz";
    for(vector<studentInfo>::iterator it = students.begin();
        it!=students.end();it++)
    {
        it->_strName = "jwz";
    }
    outputCont("students modified",cout,students.begin(),students.end());

}

void Test(){
    TestMap();
    TestSet();
    TestVector();

    const int nNum = 5;
    int a[nNum] = {1,2,3,6,4};
    outputCont("Inv a",cout,a,a+nNum);
    int b[nNum] = {};

    //输出不输出到b,输出到vector中
    vector<double>vb(nNum);
    vector<double>vc(nNum);

    transInv(a, b, nNum);
    outputCont("Inv a",cout,b,b+nNum);
    transSqr(a,b,nNum);
    outputCont("Sqr a",cout,b,b+nNum);
    transInvT(a,b,nNum);
    outputCont("InvT a T",cout,b,b+nNum);

    //InvT<int> 传入一个int类型的函数InvT
    transInvT(a,a+nNum,b,InvT<int>);
    transInvT(a,a+nNum,vb.begin(),InvT<int>);
    outputCont("Inv a by iter",cout,vb.begin(),vb.end());

    transInvT(a,a+nNum,vb.begin(),MyThreshold<int>(2));
    outputCont("Inv a by treshold",cout,vb.begin(),vb.end());

    //sort:stl里自带得排序函数,默认升序排序
    sort(a,a+nNum);
    outputCont("a sorted",cout,a,a+nNum);

    //模板函数
    sort(a,a+nNum,mycomp<int>);
    outputCont("a sorted",cout,a,a+nNum);

    //greater不是一个函数,是一个类,因为要带一个(),模板类
    sort(a,a+nNum,greater<int>());
    outputCont("a sorted",cout,a,a+nNum);

    sort(a,a+nNum,MyCompC<int>());
    outputCont("a sorted",cout,a,a+nNum);

    outputCont("vb",cout,vb.begin(),vb.end());
    outputCont("vc",cout,vc.begin(),vc.end());
    vb.swap(vc);
    outputCont("vb swaped",cout,vb.begin(),vb.end());
}

结果

01 100
03 98
10 80
student set:100011 Li yue
	10002 Li si
	10003 Wang wu
	10010 Wu si
	10021 Zheng jiawen
	
students sorted:10021 Zheng jiawen
	10002 Li si
	100011 Li yue
	10003 Wang wu
	10010 Wu si
	
students modified:10021 jwz
	10002 jwz
	100011 jwz
	10003 jwz
	10010 jwz
	
Inv a:1	2	3	6	4	
Inv a:-1	-2	-3	-6	-4	
Sqr a:1	4	9	36	16	
InvT a T:-1	-2	-3	-6	-4	
Inv a by iter:-1	-2	-3	-6	-4	
Inv a by treshold:0	1	1	1	1	
a sorted:1	2	3	4	6	
a sorted:6	4	3	2	1	
a sorted:6	4	3	2	1	
a sorted:6	4	3	2	1	
vb:0	1	1	1	1	
vc:0	0	0	0	0	
vb swaped:0	0	0	0	0

6.问题及总结

  1. 问题
    开始时没有给studentInfo类构造一个输出函数,使得在调用到该类时的所有输出都会报错,最后在该类中定义了一个友元的输出函数解决了这个问题
  2. 总结
    泛型程序设计是一种重要的程序设计方式,合理利用泛型程序设计,可以大大提高软件的复用性。C++中总的来说离不开cpvt四个东西。
  • c:class,面向对象,封装性,将一定的数据方法封装,统一到一个类里
  • p:继承,
  • v:vitrual,多态性,精华所在
  • t:template,模板
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值