模板
1.1 模板的概念
模板就是建立一个通用的模具,提高复用性
1.2 函数的模板
C++提供两种模板机制:函数模板和类模板
1.2.1 函数模板的语法
语法:
template<typename/class T>
函数声明和定义
示例:
template<typename T>
void mySwap(T &a, T &b){
T temp=a;
a=b;
b=temp;
}
//两种方法使用模板
// 1、自动匹配
mySwap(a,b);
// 2、显示指定类型
mySwap<int>(a,b);
1.2.2 函数模板注意事项
注意事项:
- 自动类型拥导,必须推导出一致的数据类型T,才可以使用
- 模板必须要确定出T的数据类型,才可以使用
1.2.3 普通函数和函数模板的区别
普通函数与函数模板区别:
- 普通函数调用时可以发生自动类型转换(隐式类型转换)
- 函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
- 如果利用显示指定类型的方式,可以发生隐式类型转换
1.2.4 普通函数和函数模板的调用规则
调用规则如下:
- 1.如果函数模板和普通函数都可以实现,优先调用普通函数
- 2.可以通过空模板参数列表来强制调用函数模板
例如:mySwap<>
- 3.函数模板也可以发生重载
- 4.如果函数模板可以产生更好的匹配,优先调用函数模板
1.2.5 模板的局限性
需要对特定的类型提供具体化的操作
template<> bool myComp(Person &a, Person &b){
if(a.name==b.name)
return true;
else
return false;
}
1.3 类模板
语法:
template<typename/class T>
类
示例:
template<class NameType,class AgeType>
class Person{
public:
Person(NameType name,AgeType age){
this.name=name;
this->age=age;
}
NameType name;
AgeType age;
}
Person<string,int>p1("Tom",10);
1.3.1 类模板和函数模板的区别
类模板与函数模板区别主要有两点:
- 1.类模板没有自动类型推导的使用方式,只能显示指定
template<class NameType,class AgeType>
Person<string,int> p("",10);
- 2.类模板在模板参数列表中可以有默认参数
template<class NameType,class AgeType = int> //默认参数
Person<string> p("",10); //类模板在模板参数列表中可以有默认参数
1.3.2 类模板中的成员函数创建时机
类模板中成员函数和普通类中成员函数创建时机是有区别的:
- 普通类中的成员函数一开始就可以创建
- 类模板中的成员函数在调用时才创建
1.3.4 类模板对象做函数参数
一共有三种传入方式:
template<class T1,class T2>
class Person{
public:
Person(T1 name,T2 age):m_Name(name),m_Age(age){}
T1 m_Name;
T2 m_Age;
}
- 1.指定传入的类型:直接显示对象的数据类型
void printPerson(Person<string,int> &p){};
Person<string,int> p("",10);
printPerson(p);
- 2.参数模板化:将对象中的参数变为模板进行传递
template<class T1,class T2>
void printPerson(Person<T1,T2> &p){};
Person<string,int> p("",10);
printPerson(p);
- 3.整个类模板化:将这个对象类型模板化进行传递
template<class T>
void printPerson(T &p){};
Person<string,int> p("",10);
printPerson(p);
1.3.5 类模板与继承
当类模板碰到继承时,需要注意一下几点:
- 当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中的的类型。
- 如果不指定,编译器无法给子类分配内存
- 如果想灵活指定出父类中T的类型,子类也需变为类模板
template<class T>
class Base{
T m;
}
class Son: public Base{} //错误,必须指定父类中T的数据类型,才能继承给子类
class Son: public Base<int>{} //正确
template<class T1,class T2>
class Son2 : public Base<T1>{
T2 obj;
}
Son2<int,char> s2;
1.3.6 类模板成员函数的类外实现
template<class T1,class T2>
class Person{
public:
T1 m_Name;
T2 m_Age;
}
//构造函数的类外实现
template<class T1,class T2>
Person<T1,T2>::Person(T1 name,T2 age){} //Person<T1,T2>表示是类模板
//成员函数的类外实现
template<class T1,class T2>
void Person<T1,T2>::showPerson(){}
1.3.7 类模板分文件编写
问题:
类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到解决
解决方式:
- 1:直接包含.cpp源文件
- 2:将声明和实现写到同一个文件中,并更改后缀名为**.hpp**,hpp是约定的名称,并不是强制
1.3.8 类模板与友元
- 全局函数类内实现:直接在类内声明友元即可
//通过全局函数 打印Person
template<class T1,class T2>
class Person{
//全局函数 类内实现
friend void showPerson(Person<T1,T2> p){
cout<<p.m_Name<<p.m_Age<<endl;
}
friend void showPerson2<>(Person<T1,T2> p); //加空模板的参数列表
private:
T1 m_Name;
T2 m_Age;
}
- 全局函数类外实现:需要提前让骗译器知道全局函数的存在
//通过全局函数 打印Person
//提前让骗译器知道Person类的存在
template<class T1,class T2>
class Person;
//提前让骗译器知道showPerson2的存在
template<class T1,class T2>
void showPerson2(Person<T1,T2> p){
cout<<p.m_Name<<p.m_Age<<endl;
}
template<class T1,class T2>
class Person{
friend void showPerson2<>(Person<T1,T2> p); //加空模板的参数列表
private:
T1 m_Name;
T2 m_Age;
}
STL
2.1 STL初识
1.1 STL基本概念
- 标准模板库,建立数据结构与算法的一套标准
- 分为:容器、算法、迭代器
1.2 STL六大组件
容器、算法、迭代器、仿函数、适配器、空间配置器
- 容器:各种数据结构,如vector、list、deque、set、map等,用来存放数据。
- 算法:各种常用的算法,如sort、find、copy、for_each等
- 迭代器:扮演了容器与算法之间的胶合剂。
- 仿函数:行为类似函数,可作为算法的某种策略
- 适配器:一种用来修饰容器或者仿函数或迭代器接口的东西。
- 空间配置器:负责空间的配置与管理
2 STL容器
2.1 string
本质上是一个类,内部封装了char*
2.1.1 string构造函数
string();
string(const string &s);
string(const char* s);
string(int n,char c);
2.1.2 string赋值操作
string& operator=(const char* s); //char*类型字符串 赋值给当前的字符串
string& operator=(const string &s); //把字符串s赋给当前的字符串
string& operator=(char c); //字符赋值给当前的字符串
string& assign(const char *s); //把字符串s赋给当前的字符串
string& assign(const char *s,int n): //把字符串s的前n个字符赋给当前的字符串
string& assign(const string &s); //把字符串s赋给当前字符串
string& assign(int n, char c); //用n个字符c赋给当前字符串
2.1.3 string拼接操作
string& operator+=[const char* str); //重载+=操作符
string& operator+=(const char c); //重载+=操作符
string& operator+=(const string& str); //重载+=操作符
string& append(const char *s); //把字符串s连接到当前字符串结尾
string& append(const char *s,int n); //把字符串s的前n个字符连接到当前字符串结尾
string& append(const string &s); //同operator+=(const string& str)
string& append(const string&s,int p0s,int n); //字符串s中从p0s开始的n个字符连接到字符串结尾
2.1.4 string查找和替换
rfind: 从右往左查找; find: 从左往右查找
int find(const string& str,int pos=0) const; //查找str第一次出现位置,从pos开始查找
int find(const char* s, int pos =0) const; //查找s第一次出现位置,从pos开始查找
int find(const char* s,int pos, int n) const; //从pos位置查找s的前n个字符第一次位置
int find(const char c,int pos =0) const; //查找字符c第一次出现位置
int rfind(const string& str,int pos = npos); //查找str最后一次位置,从pos开始查找
const;int rfind(const char*s,int pos =npos) const; //查找s最后一次出现位置,从pos开始查找
int rfind(const char*s,int pos,int n) const; //从pos查找s的前n个字符最后一次位置
int rfind(const char c,int pos=8) const; //查找字符(最后一次出现位置
string& replace(int pos,int n,const string& str); //替换从pos开始n个字符为字符串str
string& replace(int pos,int n,const char* s); //替换从pos开始的n个字符为字符串s
2.1.5 string比较
比较ASCII值,=:0,>:1,<:-1
int compare(const string &s)const; //与字符串s比比较
int compare(constchar *s)const; //与字符串s比较
2.1.6 string字符存取
char& operator[](int n); //通过口方式取字符
char& at(int n); //通过at方法获取字符
2.1.7 string插入和删除
string& insert(int pos,const char* s); //插入字符串
string& insert(int pos, const string& str); //插入字符串
string& insert(int pos,int n, char c); //在指定位置插入n个字符c
string& erase(int pos,int n=npos); //删除从Pos开始的n个字符
2.1.8 string字串
string substr(intpos=8,intn=npos)const; //返回由pos开始的n个字符组成的字符串
2.2 vector
与数组很相似,但可以动态扩展,支持随机存取
容器:vector
算法:for_each
迭代器:vector<int>::iterator
vector.begin() //第一个元素的位置
vector.end() //最后一个元素的下一个位置
void myPrint(int val){
cout<<val<<endl;
}
for_each(v.begin(),v.end(),myPrint) //遍历输出
2.2.1 vector构造函数
vector<T> v; //采用模板实现类实现,默认构造函数
vector(v.begin(),v.end()); //将v[begin(), end()区间中的元素拷贝给本身。
vector(int n, elem); //构造函数将n个elem拷贝给本身
vector(const vector &vec); //拷贝构造函数。
2.2.2 vector赋值
vector& operator=(const vector &vec);//重载等号操作符
assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身。
assign(n, elem); //将n个elem拷贝赋值给本身。
2.2.3 vector容量和大小
empty(); //判断容器是否为空
capacity(); //容器的容量
size(); //返回容器中元素的个数
resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。//如果容器变短,则末尾超出容器长度的元素被删除。//重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
resize(int num,elem);//如果容器变短,则末尾超出容器长度的元素被删除
2.4.4 vector插入和删除
push_back(ele); //尾部插入元素ele
pop_back(); //删除最后一个元素
insert(const iterator pos, ele); //迭代器指向位置pos插入元素ele
insert(const iterator pos,int count,ele);//迭代器指向位置p0s插入count个元素ele
erase(const iterator pos); //删除迭代器指向的元素
erase(const_iterator start,const_iterator end);//删除选代器从start到end之间的元素
clear();
//删除容器中所有元素
2.2.5 vector数据存取
at(int idx); //返回索引idx所指的数据
operator[idx]; //返回索引idx所指的数据
front(); //返回容器中第一个数据元素
back(); //返回容器中最后一个数据元素
2.2.6 vector互换容器
swap(vec); //将vec与本身的元素互换
巧用swap:vector<int>(v).swap(v); //收缩容量空间
2.2.7 vector预留空间
减少vector再动态扩展容量时的扩展次数
reserve(int len); //容器预留len个元素长度,预留位置不初始化,元素不可访问
2.3 deque
双端数组,可以再头部进行插入删除操作
2.3.1 deque构造函数
deque<T> deqT; //默认构造形式
deque(beg, end); //构造函数将[beg,end)区间中的元素拷贝给本身,
deque(n, elem); //构造函数将n个elem拷贝给本身
deque(const deque °); //拷贝构造函数
2.3.2 deque赋值操作
deque& operator:(const deque °); //重载等号操作符
assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身,
assign(n, elem); //将n个elem拷贝赋值给本身,
2.3.3 deque大小容量
deque.empty(); //判断容器是否为空
deque.size(); //返回容器中元素的个数
deque.resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。//如果容器变短,则末尾超出容器长度的元素被删除。
deque.resize(num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置,//如果容器变短,则末尾超出容器长度的元素被删除。
2.3.4 deque插入删除
两端插入操作:
push_back(elem); //在容器尾部添加一个数据
push_front(elem); //在容器头部插入一个数据
pop_back(); //删除容器最后一个数据
pop_front(); //删除容器第一个数据
指定位置操作:
insert(pos,elem); //在pos位置插入一个elem元素的拷贝,返回新数据的位置。
insert(pos,n,elem); //在pos位置插入n个elem数据,无返回值,
insert(pos,beg,end); //在pos位置插入[beg,end)区间的数据,无返回值。
clear(); //清空容器的所有数据
erase(beg,end); //删除[beg,end)区间的数据,返回下一个数据的位置。
erase(pos); //删除pos位置的数据,返回下一个数据的位置,
2.3.5 deque数据存取
at(int idx); //返回素引idx所指的数据
operator[]; //返回索引idx所指的数据
front(); //返回容器中第一个数据元素
back(); //返回容器中最后一个数据元素
2.3.6 deque排序
sort(iterator beg,iterator end); //对beg和end区间内元素进行排序
2.4 stack
栈容器,先进后出
2.4.1 stack常用接口
构造函数:
stack<T> pstk; //stack采用模板类实现,stack对象的默认构造形式
stack(const stack &stk); //拷贝构造函数
赋值操作:
stack& operator=(const stack &stk); //重载等号操作符
数据存取:
push(elem); //向栈顶添加元素
pop(); //从栈顶移除第一个元素
top(); //返回栈顶元素
大小操作:
empty(); //判断堆栈是否为空
size(); //返回栈的大小
2.4 queue
队列容器,先进先出,队头出数据,队尾入数据
2.4.1 queue常用接口
构造函数:
queue<T> que; //queue采用模板类实现,queue对象的默认构造形式
queue(const queue &que); //拷贝构造函数
赋值操作:
queue& operator=(const gueue &que); //重载等号操作符
数据存取:
push(elem); //往队尾添加元素
pop(); //从队头移除第一个元素
back(); //返回最后一个元素
front(); //返回第一个元素
大小操作:
empty(); //判断堆栈是否为空
size(); //返回栈的大小
2.5 list
链表容器,链式存储,STL中是双向循环链表
插入删除操作不会造成原有list迭代器失效
2.5.1 list构造函数
list<T> lst; //list采用采用模板类实现,对象的默认构造形式:
list(beg,end); //构造函数将[beg, end)区间中的元素拷贝给本身
list(n,elem); //构造函数将n个elem拷贝给本身。
list(const list &lst); //拷贝构造函数。
2.5.2 list赋值和交换
list& operator=(const list &lst); //重载等号操作符
assign(beg, end); //将[beg, end)区间中的数据拷贝赋值给本身
assign(n, elem); //将n个elem拷贝赋值给本身,
swap(lst); //将lst与本身的元素互换。
2.5.3 list大小
size(); //返回容器中元素的个数
empty(); //判断容器是否为空
resize(num); //重新指定容器的长度为num,若容器变长,则以默认值填充新位置//如果容器变短,则未尾超出容器长度的元素被删除。
resize(num, elem); //重新指走容器的长度为num,若容器变长,则以elem值填充新位置,//如果容器变短,则末尾超出容器长度的元素被删除。
2.5.4 list插入删除
push_back(elem);//在容器尾部加入一个元素
pop_back();//别除容器中最后一个元素
push_front(elem);//在容器开头插入一个元素
pop_front();//从容器开头移除第一个元素
insert(pos,elem);//在pos位置插elem元素的拷贝,返回新数据的位置。insert(pos,n,elem);//在pOS位置插入n个elem数据,无返回值,insert(pos,beg,end);//在pos位置插入[beg,end)区间的数据,无返回值。
clear();//移除容器的所有数据
erase(beg,end);//删除[beg,end)区间的数据,返回下一个数据的位置,
erase(pos);//删除pos位置的数据,返回下一个数据的位置:
remove(elem);//删除容器中所有与elem值匹配的元素,
2.5.5 list数据存取
front(); //返回第一个元素。
back(); //返回最后一个元素。
2.5.6 list排序和反转
reverse(); //反转链表
sort(); //链表排序
2.6 set / multiset
集合容器,自动排序,底层用二叉树实现
set:不允许重复元素
multiset:允许重复元素
2.6.1 set构造、赋值、插入
set<T> st; //默认构造函数:
set(const set &st); //拷贝构造函数
set& operator=(const set &st); //重载等号操作符
2.6.2 set大小和交换
size(); //返回容器中元素的数目
empty(); //判断容器是否为空
swap(st); //交换两个集合容器
2.6.3 set插入删除
insert(elem); //在容器中插入元素 ==插入只有这一种==
clear(); //清除所有元素
erase(pos); //M除pos迭代器所指的元素,返回下一个元素的迭代器。
erase(beg, end); //删除区间[beg,end)的所有元素 ,返回下一个元素的迭代器。
erase(elem); //删除容器中值为elem的元素。
2.6.4 set查找和统计
find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end();
count(key); //统计key的元素个数
2.6.5 pair对组创建
成对出现的数据
pair<type,type>p(value1,value2 );
pair<type,type>p=make_pair( value1,value2 );
2.6.6 set排序
如何改变排序规则,利用仿函数
存放内置数据类型:
class MyCompare{
public:
bool operator()(int v1,int v2){
return v1>v2;
}
}
set<int,MyCompare> s;
s.insert(10);
...
存放自定义数据类型:
class Person{
public:
string m_Name;
int m_Height;
...
}
class MyCompare{
public:
bool operator()(const Person &p1,const Person &p2){
return p1.m_Age>p2.m_Age;
}
}
set<Person,MyCompare> s;
s.insert(p);
2.7 map / multimap
2.7.1 map基本概念
map中数据成对出现
map:不允许有重复Key
multimap:允许有重复Key
成对出现的数据
2.7.2 map构造和赋值
map<T1,T2> mp; //map默认构造函数:
map(const map &mp); //拷贝构造函数
map& operator=(const map &mp); //重载等号操作符
2.7.3 map大小和交换
size(); //返回容器中元素的数目
empty(); //判断容器是否为空
swap(st); //交换两个集合容器
2.7.4 map插入和删除
insert(elem); //在容器中插入元素。
clear(); //清除所有元素
erase(pos); //删除pos迭代器所指的元素,返回下一个元素的迭代器。
erase(beg, end); //M除区间[beg,end)的所有元素,返回下一个元素的迭代器
erase(key);//删除容器中值为key的元素。
2.7.5 map查找和统计
find(key); //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回 set.end();
count(key); //统计key的元素个数
2.7.6 map大小和交换
size(); //返回容器中元素的数目
empty(); //判断容器是否为空
swap(st); //交换两个集合容器
2.7.3 map排序
默认按key从小到大,如何改变排序规则,利用仿函数
class MyCompare{
public:
bool operator()(int v1,int v2){
return v1>v2;
}
}
map<int, int, MyCompare> m;
2.7.3 map大小和交换
size(); //返回容器中元素的数目
empty(); //判断容器是否为空
swap(st); //交换两个集合容器
3 STL-函数对象
3.1 函数对象
概念:
重载函数调用操作符的类,其对象常称为函数对象。
函数对象使用重载的()时,行为类似函数调用,也叫仿函数
本质:
函数对象(仿函数)是一个类,不是一个函数
- 函数对象像普通函数一样调用,可以有返回值
class MyAdd{
public:
int operator ()(int x,int y){
return x+y;
}
}
MyAdd myadd;
cout<< myadd(1,2) <<endl;
- 函数对象超出普通函数的概念,可以有自己的状态
class MyPrint{
public:
MyPrint(){
this->count=0;
}
void operator ()(string str){
count << str <<endl;
this->count++;
}
int count; //内部自己的状态
}
- 函数对象作为参数传递
class MyPrint{
public:
void operator ()(string str){
count << str <<endl;
this->count++;
}
}
void doPrint(MyPrint &mp, string str){
}
MyPrint mp;
doPrint(mp,"hello");
3.2 谓词
概念:
返回bool类型的仿函数称为谓词
如果operator()接受一个参数,那么叫做一元谓词
如果operator()接受两个参数,那么叫做二元谓词
//一元谓词
class GreaterFive{
public:
bool operator()(int val){
return val > 5;
}
}
voidi teste1(){
vector<int>v;
for(inti=0;i<10;i++)
v.push back(i);
vector<int>::iterator it =find(v.begin(),v.end(),GreaterFive());
if(it ==v.end())
cout<<"没找到!"<<endl;
else
cout<<“找到:"<<*it<< end1;
}
//二元谓词
class MyCompare{
public:
bool operator()(int val1, int val2){
return val1 > val2;
}
}
sort(v.begin(),v.end,MyCompare());
3.3 内建函数对象
概念:
STL内建了一些函数对象
分类:
算术仿函数
关系仿函数
逻辑仿函数
用法:
这些仿函数所产生的对象,用法和一般函数完全相同使用内建函数对象,需要引入头文#include<functional>
3.3.1 算术仿函数
功能描述:
实现四则运算
其中negate是一元运算,其他都是二元运算
仿函数原型:
- template<class T>T plus<T> //加法仿函数
- template<class T>T minus<T> //减法仿函数
- template<class T>T multiplies<T> //乘法仿函数
- template<class T>T divides<T> //除法仿函数
- template<class T>T modulus<T> //取模仿函数
- template<class T>T negate<T> //取反仿函数
示例:
negate<int> n;
n(50)
plus<int> p;
p(1,2);
3.3.2 关系仿函数
功能描述:
实现关系对比
仿函数原型:
- template<class T> bool equal to<T> //等于
- template<class T> bool not equal to<T> //不等于
- template<class T> bool greater<T> //大于
- template<class T> bool greater equal<T> //大于等于
- template<class T> bool less<T> //小于
- template<class T> bool less equal<T> //小于等于
示例:
sort(v.begin(),v.end,greater<int>());
3.3.3 逻辑仿函数
实现逻辑运算
- template<class T> bool logical_and<T> //逻辑与
- template<class T>bool logical_or<T> //逻辑或
- template<class T>bool logical_not<T> //逻辑非
4 STL-常见算法
算法主要是由头文件<algorithm> <functional> <numeric>
组成。
<algorithm>
是所有STL头文件中最大的一个,范围涉及到比较、 交换、查找、遍历操作、复制、修改等等
<numeric>
体积很小,只包括几个在序列上面进行简单数学运算的模板函数
<functional>
定义了一些模板类,用以声明函数对象。
4.1 遍历算法
for_each
遍历容器
transform
搬运容器到另一个容器中
4.1.1 for_each
for each(iterator beg,iterator end, _func);
// 遍历算法 遍历容器元素
// beg 开始迭代器
// end 结束迭代器
// func 函数或者函数对象
4.1.2 transform
功能描述:
搬运容器到另一个容器中函数原型:
transform(iterator begl,iterator end1, iterator beg2,_func);
//beg1 源容器开始迭代器
//end1 源容器结束迭代器
//beg2 目标容器开始迭代器
//_func 函数或者函数对象
4.2 查找算法
算法简介:
find
查找元素find_if
按条件查找元素adjacent_find
查找相邻重复元素binary_search
二分查找法count
统计元素个数count_if
按条件统计元素个数
4.3 排序算法
算法简介:
sort
对容器内元素进行排序random_shuffle
洗牌 指定范围内的元素随机调整次序merge
容器元素合并,并存储到另一容器中reverse
反转指定范围的元素
4.4 拷贝和替换算法
算法简介:
copy
容器内指定范围的元素拷贝到另一容器中replace
将容器内指定范围的旧元素修改为新元素replace_if
容器内指定范围满足条件的元素替换为新元素swap
互换两个容器的元素
4.5 算术生成算法
算法简介:
accumulate
计算容器元素累计总和fill
向容器中添加元素
4.6 集合算法
算法简介:
set_intersection
求两个容器的交集set_union
求两个容器的并集set_difference
求两个容器的差集