目录
一、容器与迭代器
1.1 STL
标准模板库(Standard Template Library,简称STL)定义了一套概念体系,为泛型程序设计提供了逻辑基础。
STL中的各个类模板、函数模板的参数都是用这个体系中的概念来规定的。
使用STL的模板时,类型参数既可以是C++标准库中已有的类型,也可以是自定义的类型——只要这些类型是所要求概念的模型。
STL的基本组件:
- 容器(container)
- 迭代器(iterator)
- 函数对象(function object)
- 算法(algorithms)
1.2 序列变换
取反、平方与立方
// 普通取反
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];
}
}
// 模板求平方
template <typename T>
void transInvT(T a[],T 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]*a[i]*a[i];
}
}
// 输出的函数模板
template <typename T>
void outputCont(string strNme,ostream& os, T begin, T end)
{
os<<strNme<<":";
for(;begin!=end;begin++)
{
os<<*begin<<"\t";
}
os<<endl;
}
// 第二种写法
// 任何容器都可以使用该算法
template <typename inputIter, typename outputIter>
void transInvT(inputIter begInput, inputIter endInput,outputIter begOutPut)
{
for(;begInput != endInput; begInput++, begOutPut++)
{
// 限制取反
*begOutPut = ‐ (*begInput); //求反数
}
}
// 测试函数
void Test()
{
const int N = 5;
int a[N] = {1,2,3,4,5};
outputCont("a",cout,a,a+N);
int b[N];
// 输出到vector
vector<double> vb(N);
vector<double> vc(N);
transInv(a,b,N);
outputCont("Inv a",cout,b,b+N);
transSqr(a,b,N);
outputCont("Sqr a",cout,b,b+N);
transInvT(a,b,N);
outputCont("Inv a T",cout,b,b+N);
}
输出结果:
可以看到,模板中的输出只能限制取反的输出;通过改进和引入参数,我们可以通过输出一个函数的方式使得模板变得更加灵活而不仅仅是限制于取反。
template<typename T>
T InvT(T a)
{
return -a;
}
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);
}
}
1.3 像素变换
二值化
// 定义二值化阈值
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);
}
}
输出结果:0 1 1 1 1
二、set(集合)
2.1 容器的分类
序列式容器-排列次序取决于插入时机和位置
关联式容器-排列顺序取决于特定准则
2.2 集合介绍
集合用来存储一组无重复的元素。由于集合的元素本身是有序的,可以高效地查找指定元素,也可以方便地得到指定大小范围的元素在容器中所处的区间。
使用set存储学生信息,并进行增删改查操作
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;
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","Zhang san"));
students.push_back(studentInfo("10002","Li si"));
students.push_back(studentInfo("10003","Wang wu"));
students.push_back(studentInfo("10011","Wang Liu"));
students.push_back(studentInfo("10010","Wu Liu"));
set<studentInfo> studentSet(students.begin(),students.end());
outputCont("student set",cout,studentSet.begin(),studentSet.end());
}
void TestVector()
{
vector<studentInfo> students;
students.push_back(studentInfo("10021","Zhang san"));
students.push_back(studentInfo("10002","Li si"));
students.push_back(studentInfo("10003","Wang wu"));
students.push_back(studentInfo("10011","Wang Liu"));
students.push_back(studentInfo("10010","Wu Liu"));
// 自定义排序
vector<studentInfo>::iterator it = students.begin();
advance(it,2);
sort(it, students.end());
outputCont("students sorted",cout,students.begin(),students.end());
// 更改学生姓名
students[2]._strName = "zy";
for(vector<studentInfo>::iterator it=students.begin();
it!=students.end();it++)
{
it->_strName = "zy";
}
outputCont("students modified",cout,students.begin(),students.end());
}
void Test()
{
TestVector();
}
输出结果:
三、map(映射)
3.1 映射介绍
映射与集合同属于单重关联容器,它们的主要区别在于,集合的元素类型是键本身,而映射的元素类型是由键和附加数据所构成的二元组。
在集合中按照键查找一个元素时,一般只是用来确定这个元素是否存在,而在映射中按照键查找一个元素时,除了能确定它的存在性外,还可以得到相应的附加数据。
3.2 使用map统计
void TestMap()
{
map<string,int> stu;
stu["01"] = 100;
stu["10"] = 99;
stu["05"] = 98;
stu["10"] = 95;// 不支持重复
for(map<string,int>::iterator it=stu.begin();it!=stu.end();it++)
{
cout<<it->first<<" "<<it->second<<endl;
}
}
3.2.1 map中的find函数
用于查找map中是否包含某个关键字条目,传入的参数是要查找的key,最后返回一个迭代器,如果没有找到,则返回的迭代器等于end()返回的迭代器。
#include<iostream>
#include<string>
#include<map>
using namespace std;
int main() {
map<int, string> mapStudent;
mapStudent.insert(pair<int, string>(1, "student_one"));
mapStudent.insert(pair<int, string>(2, "student_two"));
mapStudent.insert(pair<int, string>(3, "student_three"));
map<int, string>::iterator iter;
iter = mapStudent.find(3);
if (iter != mapStudent.end())//只要返回的不是end()的迭代器表示已经找到了
cout << "Find,the value is: " << iter->second << endl;
while (1);
}
3.2.2 map的插入方法
主要有四种,参考:https://blog.csdn.net/F_Z_M/article/details/78119514
主要使用:map.insert(pair<type1,type2>(key,value)),还有一种是map[key] = value,前者出现重复不会发生改变,后者出现重复则会发生覆盖。后者如果没有给value值,直接使用map[key],则其value值默认为0。
#include<iostream>
#include<string>
#include<map>
using namespace std;
int main() {
map<int, string> mapStudent;
mapStudent.insert(pair<int, string>(1, "student_one"));
mapStudent.insert(pair<int, string>(2, "student_two"));
mapStudent.insert(pair<int, string>(2, "xxooxxooxxo"));//不起作用
map<int, string>::iterator iter;
for (iter = mapStudent.begin(); iter != mapStudent.end(); iter++) {
cout << iter->first << ' ' << iter->second<<endl;
}
cout << endl;
mapStudent[2] = "xxooxxooxxoo";//覆盖掉前面的value
for (iter = mapStudent.begin(); iter != mapStudent.end(); iter++) {
cout << iter->first << ' ' << iter->second << endl;
}
while (1);
}
通过pair来获取是否插入成功,pair返回两个变量,第一个是map的迭代器,第二个是插入成功的标志,插入成功pair的第二个参数是true,插入失败,第二个参数为false。
pair<map<type1,type2>::iterator,bool> ret;
ret = map_s.insert(pair<type1,type2>(key,value))
if(ret.second==ture)
cout<<"插入成功"<<endl;
else
cout<<"插入失败"<<endl;
3.2.3 统计字符出现个数
方法1:先创建一个map,遍历字符串,逐个判断如果存在则count++,不存在则创建一个,让其value为1。
方法2:通过插入失败来增加字符的个数,如果插入失败则表明map中存在该字符,count++。
方法3:需要对map了解,直接使用库里提供的[]运算符重载。通过键值找节点,直接给给实值+1。
方法1:
#include<iostream>
#include<string>
#include<map>
using namespace std;
int main() {
string str;
map<char, int> map_s;
while (cin >> str) {
for (int i = 0; i < str.length(); ++i) {
map<char, int>::iterator iter = map_s.find(str[i]);
if (iter != map_s.end()) {//如果iter返回不是是map_s.end()表示找到了
iter->second++;
}
else {//如果找不到就添加一个,找到了就count++
map_s.insert(pair<char, int>(str[i], 1)); }
}
map<char, int>::iterator iter = map_s.begin();
for (; iter != map_s.end(); iter++) {
cout << iter->first << ' ' << iter->second << endl;
}
cout << endl;
}
}
方法2:
#include<iostream>
#include<string>
#include<map>
using namespace std;
int main() {
string str;
map<char, int> map_s;
while (cin >> str) {
pair<map<char, int>::iterator, bool> ret;
for (int i = 0; i < str.length(); ++i) {
ret = map_s.insert(pair<char, int>(str[i], 1));
if (ret.second == false) {//如果插入失败,则该迭代器的第一个参数的value++
ret.first->second++;
}
}
map<char, int>::iterator iter = map_s.begin();
for (; iter != map_s.end(); iter++) {
cout << iter->first << ' ' << iter->second << endl;
}
cout << endl;
}
}
方法3:
#include<iostream>
#include<string>
#include<map>
using namespace std;
int main() {
string str;
map<char, int> map_s;
while (cin >> str) {
for (int i = 0; i < str.length(); ++i) {
map_s[str[i]]++;
}
map<char, int>::iterator iter;
for (iter = map_s.begin(); iter != map_s.end(); ++iter) {
cout << iter->first << ':' << iter->second << endl;
}
}
}
输出结果:
四、c++总结
STL算法特点:
STL算法本身是一种函数模版。
- 通过迭代器获得输入数据
- 通过函数对象对数据进行处理
- 通过迭代器将结果输出
STL算法是通用的,独立于具体的数据类型、容器类型。
STL算法分类:
- 不可变序列算法
- 可变序列算法
- 排序和搜索算法
- 数值算法
C++课程知识总结——cpvt
template<typename T>
class B: public A
{
public:
virtual void do();
private:
};