函数模板
与普通函数区别:
1.普通函数调用存在隐式类型转换
2.自动类型推导调用时,不发生隐式类型转换
3.显示指定类型调用可以发生隐式类型转换
与普通函数重名时:
1,.默认调用普通函数
2.通过空模板参数类表(Max<>)强制调用函数模板
3.函数模板可发生重载(参数个数不同)
4.函数模板可产生更好的匹配时优先调用函数模板
例:普通函数:void Fun(int a,int b){}
函数模板:template
调用Fun(a,b)//a,b为char类型时普通函数需隐式转换int为char,函数模板只需将T制定为char类型,即优先调用函数模板。
模板局限性:如自定义类型对比(解决方法1.在自定义类型中重置内置运算符,2.利用具体化模板实现代码)=>template <> bool Compare(Person p1,Person p2)
{
if(p1.name ==p2.name&&p1.age == p2.age)
return true;
else
return false;
};
声明格式:
template
//需要不同类型参数时<typename T1,typename T2>u77
返回值 函数名 (形参表)
{
函数体;
}
template
T Max(T Inpute1, T Inpuet2)
{
return (Inpute1 > Inpute2) ? Inpute1 : Inpute2;
}
使用:
1.自动类型推导
Max(a,b);
2.显示指定类型
Max
类模板//与函数模板区别:1.没有自动类型推导,
2.在模板参数列表中可以有默认参数template
template
class 类名
{
类定义;
}
template <class T1,class T2>
class Person
{
public:
Person(T1 name,T2 age)
{
this->Name = name;
this->Age =age;
}
void ShowPerson(T1 name,T2 age);
private:
T1 Name;
T2 Age;
}
在类外定义成员函数时:
template
返回值类型 类名
{
函数体;
}
template <typename T1, typenme T2>
void Person<T1,T2>::ShowPerson(T1 name,T2 age)
{
cout<<name<<age<<endl;
}
类模板声明对象:
类名<泛型数据类型> 对象名;
Person<string,int> p ("Wei",17);
类模板对象作为函数参数
1.指定传入类型
void PrintPerson(Person<string ,int> &p)
{
p.ShowPerson(p.name,p.age);
}
2.参数模板化
template <class T1,class T2>
void PrintPerson(Person<T1 ,T3> &p)
{
p.ShowPerson(p.name,p.age);
}
3.整个类模板化
template
void PrintPerson(T &p)
{
p.ShowPerson(p.name,p.age);
}
类模板与继承
1.当子类继承的父类为一个类模板时,子类在声明时必须指定父类中T的类型。
template
class Base
{
T m;
}
class Son :public Base
{
};
2.如果不指定 ,编译器无法为子类分配内存。
3.如想灵活指定父类T类型,则需将子类也定义为类模板。
template <class T1, class T2>//子类也定义为类模板
class Son :public Base
{
T1 obj;
};
Son<int,char> s1;
——————————————————————————————————————
STL
Vector:单端数组,动态拓展:开辟一块更大的空间拷贝数据,释放原来空间。
迭代器:v.begin()//指向容器首位置
v.end()//指向容器最后一位的下一个位置
v.rend()//首位的前一位置
v.rbegin()//指向最后一位元素
支持随机访问
构造函数:
vector
vector(v.begin(),v.end())// 将v的首末拷贝到本身
vector(n,elem)// 将n个elem拷贝给本身
vector(const vector &vec)// 拷贝构造函数
赋值操作:
operator=
v.assign(v1.begin(), v1.end())
v.assign(n,elem);
容量大小方法:
empty()//判断容易是否为空;
capacity()//容器容量
size()//容器中元素的个数
resize(int num)//重新制定容器的长度为num
resize(int num elem)//重新定义容器长度,并默认以elem填充
插入/删除方法:
push_back(ele);//在尾部插入数据
pop_back()//在尾部删除数据
insert(const_iterator pos, ele)//在迭代器所指向位置插入ele
insert(const_iterator pos, int count, ele)//在迭代器所指向位置插入count个ele
erase(const_iterator pos);//删除迭代器所指向的元素
erase(const_iterator start, const_iterator end)//清除迭代器s-e之间的元素
clear();//清空元素
#include
#include "pch.cpp"
#include
#include
using namespace std;
int main()
{
//cout << "WEI" << endl;
Fun1();
return 0;
}
void Fun1()
{
//创建Vector容器
vector
//向容器中插入数据
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
v.push_back(50);
////通过迭代器访问容器中的数据
//vector<int >::iterator itBegin = v.begin();//起始迭代器,指向容器第一个元素
//vector<int >::iterator itEnd = v.end();//结束迭代器,指向最后一个元素的下一个位置
////遍历方式
//while (itBegin != itEnd)
//{
// cout << *itBegin << endl;
// itBegin++;
//}
//遍历方式二
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << endl;
}
//第三种 STL提供的遍历算法
for_each (v.begin(), v.end(), MyPrint);
}
void MyPrint(int var)
{
cout << var << endl;
}
C++链表List
优点:可在任意位置插入大量元素,修改指针即可不需要移动大量元素;动态内存分配,不会造成内存浪费和溢出
缺点:空间(占用空间比较大),时间(遍历速度慢)的额外消耗较大;插入和删除操作不会造成原来的迭代器失效,这在vector中是不成立的(数组装满后会开辟新的更大的空间拷贝源数据,但迭代器仍指向原地址)
//遍历方法
void MyList::printList(const list
{
for (list
{
cout << *it << " ";
}
cout << endl;
}
void MyList::List()
{
//创建Lis容器
list
//添加数据
Li.push_back(10);
Li.push_back(20);
Li.push_back(30);
Li.push_back(40);
//遍历容器
printList(Li);
//区间构造
list<int> L2(Li.begin(), Li.end());
printList(L2);
//拷贝构造
list<int > L3 (L2);
printList(L3);
//N个ELE构造
list<int> L4(10, 999);
printList(L4);
//**赋值 **=
list<int> L5;
L5 = L4;
//区间
list<int> L6;
L6.assign(L4.begin(), L4.end());
//n*Ele
list<int> L7;
L7.assign(5, 7);
//交换
printList(L6);
printList(L7);
L7.swap(L6);
printList(L6);
printList(L7);
//**list大小操作**
cout<<L7.size()<<endl;//返回容器元素个数
cout << L7.empty()<<endl;//容器是否为空
L7.resize(7);//重新定义容器长度,多则0填充,少则从末尾删除
printList(L7);
L7.resize(10, 777);//重新定义容器长度,多则ele填充,少则从末尾删除
printList(L7);
//**插入/删除**
list<int> insDle(5,7);
//头插
insDle.push_front(3);
insDle.push_front(2);
insDle.push_front(1);
//尾插
insDle.push_back(7);
insDle.push_back(8);
insDle.push_back(9);
printList(insDle);
//尾删除
insDle.pop_back();
//头部删除
insDle.pop_front();
printList(insDle);
//insert插入
list<int>::iterator it = insDle.begin();
insDle.insert(++it, 23);
printList(insDle);
//删除
it = insDle.begin();
insDle.erase(it);
printList(insDle);
//移除所有同样的元素
insDle.remove(7);
printList(insDle);
//清空
insDle.clear();
printList(insDle);
//数据存取
L7.front();
L7.back();
list<int>::iterator Linklist_it = L7.begin();
Linklist_it++;//支持双向
Linklist_it--;//不支持--则为单相访问
//Linklist_it = Linklist_it + 1;//可以这样写着表示可以支持随机访问,链表不支持随机访问。
//链表反转/排序
printList(L7);
L7.reverse();
printList(L7);
//排序
list<int> ls;
ls.push_back(3);
ls.push_back(1);
ls.push_back(2);
//所有不支持随机访问到迭代器的容器,不支持标准算法
//容器内部会提供对应的一些算法
ls.sort();//默认升生序排序
//MyList l;
//ls.sort(l.MyCompare);
printList(ls);
}
}
例:两数之和LC
list<int> TowAddList(list<int>* l1, list<int>* l2)
{
list
list
list
int digit = 0;
while (pos1!=l1->end()||pos2!=l2->end())
{
int total = digit;
if (pos1 != l1->end())
{
total += *pos1;
pos1++;
}
if (pos2 != l2->end())
{
total += *pos2;
pos2++;
}
digit = total / 10;
res.push_back(total % 10);
}
if (digit != 0)
{
res.push_back(digit);
}
return res;
}
—————————————————————————————————————————
哈希表/(键值对)
map/multimap:元素为pair键值对,底层容器由二叉树实现
优点:根据key可以快速找到value
map不允许有重复的key
multimap允许有重复的key
class MyTable
{
public:
void MapText()
{
//默认构造
map<int, string> m1;//map会根据键的值进行默认的排序,与先后插入顺序无关
m1.insert(pair<int, string>(1, "A"));
m1.insert(pair<int, string>(3, "C"));
m1.insert(map<int, string>::value_type(2,"B"));
//m1.insert(pair<int, string>(3, "C"));
m1.insert(pair<int, string>(7, "W"));
printMap(m1);
//拷贝构造
map<int, string>m2(m1);
printMap(m2);
//赋值
map<int, string> m3 = m2;
m3.erase(7);
m3.insert(pair<int ,string>(11, "Z"));
printMap(m3);
//大小和交换
cout << m1.size()<<endl;
cout << m1.empty()<<endl;
m2.swap(m3);
printMap(m2);
printMap(m3);
//插入/删除
map<int, string> m7;
m7.insert(pair<int ,string>(1, "A"));
m7.insert(pair(2, "B"));
m7.insert(make_pair(3, "C"));
m7.insert(map<int, string>::value_type(7, "W"));
m7[5] = "Z";//不存在Key时,会创建该键值为类型默认值,不建议使用,可以用来读取键中的值
printMap(m7);
//删除
m7.erase(m7.begin());
m7.erase(3);//按照key删除
//m7.erase(m7.begin(), m7.end());
//m7.clear();
m7.insert(pair(17, "Z"));
printMap(m7);
//查找,返回值为迭代器,未找到2时返回容器的end()
map<int, string>::iterator pos = m7.find(7);
if (pos != m7.end())
cout << (*pos).first <<" "<<(*pos).second << endl;
//统计,1/0,multimap允许键重复适用此方法
int n = m7.count(7);
cout << n << endl;
}
void printMap(map<int, string> m)
{
for (map<int, string>::iterator it = m.begin(); it != m.end(); it++)
{
cout << "KEY: "<<(*it).first <<" "<< "Value:"<<(*it).second<<endl;
}
cout << endl;
}
};
//改为降序排序的仿函数
class MyMapSort
{
public:
bool operator() (int a,int b)
{
//降序:第一个数大于第二个数
return a > b;
}
};
void textmap()
{
map<int, int,MyMapSort> m;//默认按照键从小到大排序
m.insert(pair(1, 1));
m.insert(pair(3, 3));
m.insert(pair(2, 2));
//m.insert(pair(3, 3));
m.insert(pair(4, 4));
m.insert(pair(5, 5));
for (map<int,int, MyMapSort>::iterator it = m.begin(); it!=m.end(); it++)
{
cout << "key:" << (*it).first << " " << (*it).second << endl;
}
}