- 函数模板
- 函数模板之冒泡排序
- 类模板各种情况1.0
- 类模板各种情况2.0
- STL标准模板库
- 标准模板库之容器
- sequence序列容器
- list 链表
- vector 动态数组/向量
- deque 队列
- associative关联容器
- map
- 容器查阅文档见下:
- sequence序列容器
- list
- vector
- deque
- associative关联容器
- map
- set
- 容器-迭代器-算法 ——关系表
#include
#include
using namespace std;
// template:定义模板的关键字
// typename:定义模板类型的关键字
// TT:通用的类型,在调用函数进行使用的时候会根据所给的参数类型自动匹配
// :模板的参数列表,需要多个参数的话就加逗号继续写,比如template
// PS:要紧挨着需要使用函数模板的函数(上下行,中间尽量别写乱七八糟的东西)
// 如果函数声明和定义是分开的,那么函数模板的那句话在声明和定义的部分都要加上。
template<typename TT>
TT Add(TT a, TT b) {
TT c = a + b;
return c;
}
template<typename TT,typename KK>
TT Add(TT a, TT b, KK d) {
TT c = a + b;
return c;
}
//double Add(double a, double b) {
// return a + b;
//}
template<typename TT>
void show(TT a, int b = 10);
//函数体加了模板但函数内无,无法自动推导TT的类型~,所以要指定类型
template<typename TT=int>
TT show1() {
cout << "show1" << endl;
return 0;
}
// c++98编译失败(仅允许在类模板上使用默认模板参数),但目前c++11已经解除该限制,C++11支持了函数模板的默认模板参数,此处可以编译通过。
// PS:尽管C++11支持了函数模板的默认模板参数,不过在语法上,两者还是存在区别:类模板在为多个默认模板参数声明指定默认值时,必须遵照“从右往左”的规则进行指定。
而这个规则对函数模板来说并不是必须的~对于函数模板来说,默认模板参数的位置则比较随意~
// 如果能够从函数实参中推导出类型的话,那么默认模板参数就不会被使用,反之,默认模板参数则可能会被使用。
//C++98的解决方式:
//template
//TT show1() {
// cout << "show1" << endl;
// return 0;
//}
//
//调用时在函数后面加上<默认的参数类型>使用,如:show1();
//函数内加了模板 但函数体无 无法自动推导TT的类型~,所以要指定类型,调用时在函数后面加上<默认的参数类型>使用
template<typename TT>
void show2(int a) {
TT c = 30;
cout << "show2" << c << endl;
}
template<typename TT>
void show3(TT a) {
TT c = a;
cout << "show3" << c << endl;
}
template<typename TT, typename KK>
void show4(TT a) {
TT c = a;
KK d = 10;
cout << "show4" << c << d << endl;
}
int main() {
int a = 10, b = 20;
cout << Add(a, b) << endl;
double c = 10.1, d = 10.2;
cout << Add(c, d) << endl;
Add(a, b, d);//此时根据参数匹配,TT就会是int类型,KK是double类型~
char k = 50;
show(k, 20);
show1();
//RTTI 动态类型识别
//cout << typeid(show1()).name() << endl;
//cout << typeid(show1()).name() << endl;
show2<double>(48);
show3(48); //默认推导是int类型 但想用别的类型来存 也可以用<类型>的方式
show3<char>(48);
//show4(48);
//报错,函数模板参数列表多个,那类型也就需要指定多个~如下:
show4<char, double>(48);
system("pause");
return 0;
}
template<typename TT>
void show(TT a, int b) {
cout << a << endl;
cout << b << endl;
}
函数模板参考资料(注意下C++11的一些更新~)
函数模板之冒泡排序#include
using namespace std;
#include
#include
template<typename TT>
bool rule(TT a, TT b)
{
return a < b;
}
bool rule1(int a, int b)
{
return a > b;
}
bool rule2(double a, double b)
{
return a > b;
}
template<typename TT>
void BubbleSort(TT* pArr, int length, bool(*p_fun)(TT, TT)) {
if (pArr == NULL || length <= 0) {
return;
}
for (int i = 0; i < length - 1; i++)
{
for (int j = 0; j < length - 1 - i; j++)
{
//if (pArr[j] < pArr[j + 1]) //从大到小
//if (pArr[j] > pArr[j + 1]) //从小到大
if ((*p_fun)(pArr[j], pArr[j + 1]))
{
TT temp = pArr[j];
pArr[j] = pArr[j + 1];
pArr[j + 1] = temp;
}
}
}
}
//void show(int a) { //参数是每个结点里值的类型~
//
//}
//
//list lst;
//lst.push_back(1);
//lst.push_back(2);
//::for_each(lst.begin(), lst.end(), &show);
::for_each注意要使用头文件#include 噢~
次函数的三个参数是 头 尾 自己指定写的函数,参考该思想来改写冒泡排序,以求能达到能够自己选择是从大到小还是从小到大进行排序~
int main() {
int arr[10] = { 2,7,8,1,0,9,6,3,4,5 };
BubbleSort(arr, 10, &rule<int>);
for (int val : arr) // 从arr里面取出元素放在val里,可以有效避免数组越界
// (数组越界即:arr[i],但是i的值大于数组的大小)
{
cout << val << " ";
}cout << endl;
BubbleSort(arr, 10, &rule1);
for (int val : arr)
{
cout << val << " ";
}cout << endl;
double arr1[10] = { 2.2,7.7,8.8,1.1,0.1,9.9,6.6,3.3,4.4,5.5 };
BubbleSort(arr1, 10, &rule);
for (double val : arr1)
{
cout << val << " ";
}cout << endl;
BubbleSort(arr1, 10, &rule2) ;
for (double val : arr1)
{
cout << val << " ";
}cout << endl;
system("pause");
return 0;
}
类模板各种情况1.0
#include
using namespace std;
#include
//从右往左依次指定,不能间断
//如果类模板参数列表都已经默认指定,如:template,那么如果函数调用时不想使用默认要重新指定的话,要么两个都重新指定,要么重新指定KK,不会出现指定TT而KK默认的情况,因为从右往左依次指定,不能间断。
//template
template<typename TT=int, typename KK = double>
class CTest
{
public:
TT m_a;
KK m_k;
public:
CTest() {
m_a = 10;
}
CTest(TT t,KK k) {
m_a = t;
m_k = k;
}
public:
void show(TT tt) {
TT t = 20;
cout << t << " " << typeid(t).name() << endl;
cout << tt << " " << typeid(tt).name() << endl;
}
void get() {
cout << m_a << " " << typeid(m_a).name() << endl;
cout << m_k << " " << typeid(m_k).name() << endl;
}
void play();
void play1(TT t, KK k);
template<typename MM>
void Test(MM mm) {
MM m = 30;
cout << m << " " << mm << " " << typeid(m).name() << endl;
}
template<typename HH>
void Test1() {
HH hh = 20;
cout << hh << " " << typeid(hh).name() << endl;
}
template<typename NN>
void Name(TT t, KK k);
};
//void CTest::play() { //报错:缺少类模板的参数列表
//void CTest::play() {
// cout << m_a << " " << typeid(m_a).name() << endl;
// cout << m_k << " " << typeid(m_k).name() << endl;
//}
//不能在类外部的类模板成员声明上指定默认的模板参数类型
//template
template<typename TT , typename KK>
void CTest<TT,KK>::play() {
cout << m_a << " " << typeid(m_a).name() << endl;
cout << m_k << " " << typeid(m_k).name() << endl;
}
template<typename TT, typename KK>
void CTest<TT, KK>::play1(TT t, KK k) {
cout << m_a+t << " " << typeid(m_a).name() << endl;
cout << m_k+k << " " << typeid(m_k).name() << endl;
}
//类模板+函数模板时 注意模板声明的顺序
template<typename TT, typename KK>
template<typename NN>
void CTest<TT, KK>::Name(TT t, KK k) {
NN n = 50;
cout << m_a << " " << typeid(m_a).name() << endl;
cout << m_k << " " << typeid(m_k).name() << endl;
cout << n << " " << typeid(n).name() << endl;
}
int main() {
CTest tst;
报错:因为不知道TT的类型,所以用类创建对象时也无法确定空间
//CTest tst;
能明显看出类似于list lst;
实际上封装好的list也是一个模板类~
//cout << tst.m_a << endl;
//tst.show(10);
//CTest tst2(3.14,'A');
//tst2.get();
//CTest tst2(3.14, 5);
//tst2.get();
//CTest tst2(3.14, 10);
指定了那就用指定的,没指定就用默认的
//tst2.get();
CTest< > tst(20, 3.14);
//类模板参数列表多个,此时想要都用默认的时候注意要加< >,如果不加也无法编译通过
tst.get();
tst.play();
CTest<char, int> tst2('A', 30);
tst2.play();
//报错:void CTest::play() ,该函数没有实现,实际上我们所实现的只有void CTest::play() ,那么如何让play函数具备拓展复用性?
//解决方法:在play函数上加上函数模板,注意该处的参数列表不要设置默认类型噢~
CTest<char, int> tst3('A', 30);
tst3.play1('0', 20);
tst3.Test(10);
tst3.Test1<long>();
tst3.Name<long>('0',5);
system("pause");
return 0;
}
类模板各种情况2.0
#include
using namespace std;
#include
template<typename TT>
class CTestAA
{
public:
TT m_T;
public:
CTestAA() {
m_T = 20;
}
};
template<typename KK>
class CTestBB
{
public:
CTestAA<KK> m_a;
};
template<typename MM,typename NN>
class CTestCC
{
public:
MM m_m;
NN m_n;
CTestCC(MM m, NN n) {
m_m = m;
m_n = n;
}
};
int main() {
CTestBB<int> tstBB;
cout << tstBB.m_a.m_T << " " << typeid(tstBB.m_a.m_T).name() << " " << typeid(tstBB.m_a).name() << endl;
CTestAA<int> aa;
CTestCC<CTestAA<int>, int> tstCC(aa,10);
cout << tstCC.m_m.m_T << " " << typeid(tstCC.m_m.m_T).name() << " " << tstCC.m_n << " " << typeid(tstCC.m_n).name() << endl;
system("pause");
return 0;
}
STL标准模板库
-
STL——Standard Template Library——标准模板库
-
六组件
- 容器 Containers
- 迭代器 Iterators
- 算法 Algorithms
- 容器适配器 Container Adapters
- 分配器/空间适配器 Allocators
- 仿函数 Function Objects
-
sequence序列容器:list/vector/deque
- 保持了元素在容器中的原始位置,允许在容器中指定插入的位置,每个元素都有固定的位置,取决于插入的时间地点,和元素的值无关。
- 保持了元素在容器中的原始位置,允许在容器中指定插入的位置,每个元素都有固定的位置,取决于插入的时间地点,和元素的值无关。
-
associative关联容器:map/set/hash_map
- 元素插入的位置取决于特定的排序规则。
- 元素插入的位置取决于特定的排序规则。
#include
using namespace std;
#include
#include
bool rule(int a, int b) {
return a > b;
}
void show(int a) {
cout << a << " ";
}
int main() {
list<int> lst;
lst.push_back(1);
lst.push_back(8);
lst.push_back(8);
lst.push_back(5);
lst.push_back(3);
lst.sort();
//lst.sort(&rule);
//::for_each(lst.begin(), lst.end(), &show); cout << endl;
//lst.remove(3); //移除固定的值
//::for_each(lst.begin(), lst.end(), &show); cout << endl;
//lst.unique(); //连续且相同 只保留一个
//::for_each(lst.begin(), lst.end(), &show); cout << endl;
//lst.sort(); //默认升序,可通过设定规则确认升序降序
//::for_each(lst.begin(), lst.end(), &show); cout << endl;
//lst.reverse(); //翻转
//::for_each(lst.begin(), lst.end(), &show); cout << endl;
//lst.sort(&rule); //指定规则降序排序
//::for_each(lst.begin(), lst.end(), &show); cout << endl;
list<int> lst2;
lst2.push_back(60);
lst2.push_back(20);
lst2.push_back(50);
lst2.sort();
//lst2.sort(&rule);
//::for_each(lst2.begin(), lst2.end(), &show); cout << endl;
//lst.splice(++lst.begin(), lst2); //整个
//::for_each(lst.begin(), lst.end(), &show); cout << endl;
//::for_each(lst2.begin(), lst2.end(), &show); cout << endl; //lst2插入到lst后,lst2重载为空~ 所以该行输出无内容
//lst.splice(++lst.begin(), lst2, ++lst2.begin()); //20
//::for_each(lst.begin(), lst.end(), &show); cout << endl;
//::for_each(lst2.begin(), lst2.end(), &show); cout << endl;
//lst.splice(++lst.begin(), lst2, ++lst2.begin(), lst2.end()); //20,50
//::for_each(lst.begin(), lst.end(), &show); cout << endl;
//::for_each(lst2.begin(), lst2.end(), &show); cout << endl;
//lst.splice(++lst.begin(), lst, --lst.end()); //结尾的1插入到首8的后面
//::for_each(lst.begin(), lst.end(), &show); cout << endl;
//::for_each(lst2.begin(), lst2.end(), &show); cout << endl;
//lst.push_back(8);
//lst.push_back(5);
//lst.push_back(3);
//::for_each(lst.begin(), lst.end(), &show); cout << endl;
//8 5 1 8 5 3
//lst.splice(++lst.begin(), lst, ++(++lst.begin()), lst.end());
1 8 5 3插入到8后面
//::for_each(lst.begin(), lst.end(), &show); cout << endl;
//::for_each(lst2.begin(), lst2.end(), &show); cout << endl;
//lst.splice(++lst.begin(), lst, lst.begin(), --lst.end());
// //不报错但实际上会出现错误,也就是说范围不能是整个原链表~
//::for_each(lst.begin(), lst.end(), &show); cout << endl;
//::for_each(lst2.begin(), lst2.end(), &show); cout << endl;
//lst.merge(lst2);
// //两个list的内容都必须先经过递增排序,该函数是合并两个链表整体进行排序,默认的是递增~也可以指定降序,如果降序的话那么两个list的内容先需要经过降序排序
//::for_each(lst.begin(), lst.end(), &show); cout << endl;
//lst.merge(lst2, &rule);
//::for_each(lst.begin(), lst.end(), &show); cout << endl;
lst.swap(lst2); //交换两链表内的元素 写法一~
swap(lst, lst2); //写法二~
::for_each(lst.begin(), lst.end(), &show); cout << endl;
::for_each(lst2.begin(), lst2.end(), &show); cout << endl;
system("pause");
return 0;
}
vector 动态数组/向量
#include
using namespace std;
#include
#include
//vector 动态数组
void show(int a) {
cout << a << " ";
}
int main() {
//vector vec; // size<=容量
//cout << vec.size() << " " << vec.capacity() << endl; // 0 0
//vector vec(2); // 构造元素的数量但未给出初始化的值,因此默认是0
//cout << vec.size() << " " << vec.capacity() << endl; // 2 2
//vector::iterator ite = vec.begin();
//while (ite != vec.end())
//{
// cout << *ite << " ";
// ite++;
//}cout << endl; // 0 0
vector<int> vec(2, 4); // 构造元素的数量并给出初始化的值4
cout << vec.size() << " " << vec.capacity() << endl; // 2 2
vector<int>::iterator ite = vec.begin();
while (ite != vec.end()) //遍历 方法1
{
cout << *ite << " ";
ite++;
}cout << endl; // 4 4
vec.push_back(1);
vec.push_back(2);
vec.push_back(3);
for (int i = 0; i < vec.size(); i++) //遍历 方法2
{
cout << vec[i] << " ";
}cout << endl;
::for_each(vec.begin(), vec.end(), &show); //遍历 方法3
cout << endl;
cout << vec.size() << " " << vec.capacity() << endl;
// 5 6
//为什么是6不是5?其容量的扩充有其自己的规则,不是加一个元素就加一个容量噢~
//cout << vec.front() << endl;
//cout << vec.back() << endl;
//vec.pop_back();
//::for_each(vec.begin(), vec.end(), &show);
//cout << endl;
//cout << vec.size() << " " << vec.capacity() << endl;
// // 4 6
// // 删除尾部的元素时,其容量不会变化
只有pop_back尾删除和push_back尾添加~没有pop_front之类的噢
//vec.insert(++vec.begin(), 5); //4后加5
//::for_each(vec.begin(), vec.end(), &show);
//cout << endl;
//vec.insert(++vec.begin(), 2, 9); //4后加2个9
//::for_each(vec.begin(), vec.end(), &show);
//cout << endl;
//vec.erase(vec.begin()); //删除第一个元素
//::for_each(vec.begin(), vec.end(), &show);
//cout << endl;
vector<int>::iterator ite1 = ++vec.begin(); //ite1指向4
//vec.erase(ite1);
//ite1还是指向原位置,但4被删除,后面的1往前移,所以ite1指向的是1,和链表不同,链表节点删除后,指向的ite必须要用东西接一下,否则就遗失了,但此处无须用东西接,其还是指向那个位置
ite1 = vec.erase(ite1);//手贱想要接一下也会是一样的结果,还是1~
::for_each(vec.begin(), vec.end(), &show);
cout << endl;
vec.clear(); //size=0,但容量不变噢!
cout << vec.size() << " " << vec.capacity() << endl;
//Iterator find(起始位置,结束位置,查找的元素值) //找到指定的值的位置
//PS:不是vector的成员而是c++提供的一个函数噢!
//另外,vector内部也没有提供像链表一样的sort排序的功能,但是算法中提供::sort()函数。
vector<int>* pVec = new vector<int>(2, 3);
//这样new也是被允许哒,不过这个在堆区啦,上面那些是在栈区的噢~
cout << pVec->size() << " " << pVec->capacity() << endl;
system("pause");
return 0;
}
deque 队列
#include
using namespace std;
#include
#include
#include
#include
void show(int a) {
cout << a << " ";
}
int main() {
deque<int> de;
de.push_back(3);
de.push_back(6);
de.push_back(2);
de.push_back(5);
de.push_back(9);
//遍历的几种方式~
for (int i = 0; i < de.size(); i++)
{
cout << de[i] << " ";
}cout << endl;
::for_each(de.begin(), de.end(), &show);
cout << endl;
de.push_front(1);
de.push_front(2);
deque<int>::iterator ite = de.begin();
while (ite != de.end())
{
cout << *ite << " ";
ite++;
//ite += 2;
}cout << endl;
//list lst;
//lst.begin() += 2; //list没有重载+= 所以报错 可以利用advance解决(迭代器加~)
//vector vec;
//vec.begin() += 2; //vector重载了+=
ite = de.begin(); //ite 指向头
//::advance(ite, 3); //ite 偏移3
//::advance(ite, de.size() - 1);//ite 偏移到最后一个元素
//::advance(ite, de.size); //出界~ 报错了噢
cout << *ite << endl;
for (int val : de)
{
cout << val << " ";
}cout << endl;
cout << endl;
de.pop_back();
::for_each(de.begin(), de.end(), &show);
cout << endl;
de.pop_front();
::for_each(de.begin(), de.end(), &show);
cout << endl;
cout << "size:" << de.size() << endl;
de.insert(++de.begin(), 10);
::for_each(de.begin(), de.end(), &show);
cout << endl;
cout << "size:" << de.size() << endl;
de.erase(++de.begin());
::for_each(de.begin(), de.end(), &show);
cout << endl;
cout << "size:" << de.size() << endl;
de.resize(de.size() + 2);
cout << "size:" << de.size() << endl;
::for_each(de.begin(), de.end(), &show);
cout << endl;
de.resize(de.size() - 4);
cout << "size:" << de.size() << endl;
::for_each(de.begin(), de.end(), &show);
cout << endl;
de.clear();
cout << "size:" << de.size() << endl;
::for_each(de.begin(), de.end(), &show);
cout << endl;
system("pause");
return 0;
}
associative关联容器
map
#include
#include
#include
#include
using namespace std;
// 如何确定是关联性容器还是序列性容器?
// 序列性容器:元素跟插入的时间和地点,有固定的位置。
// 关联性容器:元素的位置和插入无关,有其特定的排列顺序
void show(pair<string, int> pr) {
cout << pr.first << " " << pr.second << endl;
}
int main() {
map<string, int> mm;
mm["DD"] = 100;
mm["CC"] = 200;
mm["UU"] = 300;
mm["SS"] = 400;
//遍历 //根据键值自动排序~
map<string, int>::iterator ite = mm.begin();
while (ite != mm.end()) {
cout << (*ite).first << " " << (*ite).second << endl;
ite++;
}
::for_each(mm.begin(), mm.end(), &show);
//通过键值找到实值 不再像序列性容器一样去遍历再查找~
cout << mm["DD"] << endl;
//cout << mm["OO"] << endl; // 不存在则输出0 查找效率(log2n 2为底n的对数)
//注意!此处mm["OO"]如果没有,那么就会自动加一个"OO" 0
if (mm["DD"]) {
cout << mm["DD"] << endl;
}
else {
cout << "不存在" << endl;
}
//if (mm["OO"]) { //注意!此处mm["OO"]如果没有,那么就会自动加一个"OO" 0
// cout << mm["OO"] << endl;
//}
//else {
// cout << "不存在" << endl;
//}
map<string, int>::iterator ite1 = mm.find("CC");
cout << (*ite1).first << " " << (*ite1).second << endl; //两种写法~
cout << ite1->first << " " << ite1->second << endl;
map<string, int>::iterator ite2 = mm.find("OO"); //找不到OO 会返回一个指向end()的迭代器
if (ite2 != mm.end())
{
cout << (*ite2).first << " " << (*ite2).second << endl;
cout << ite2->first << " " << ite2->second << endl;
}
cout << endl;
::for_each(mm.begin(), mm.end(), &show);
cout << endl;
pair<string, int> pr1("II", 600);
mm.insert(pr1);
::for_each(mm.begin(), mm.end(), &show);
cout << endl;
pair<string, int> pr2("PP", 500);
mm.insert(mm.begin(), pr2); //依然会自动按照键值排序,和给定的mm.begin()位置没有关系
//mm.begin()只是给出的一个起始搜索的位置(可以提高程序的效率),但该位置并不一定是真正元素插入的位置
::for_each(mm.begin(), mm.end(), &show);
cout << endl;
map<string, int>::iterator ite3 = mm.find("II");
mm.erase("II");
::for_each(mm.begin(), mm.end(), &show);
cout << endl;
if (mm.count("PP")) {
cout << mm["PP"] << endl;
}
else {
cout << "不存在" << endl;
}
cout << endl;
if (mm.count("II")) {
cout << mm["II"] << endl;
}
else {
cout << "不存在" << endl;
}
cout << endl;
cout << mm.size() << endl;
cout << endl;
::for_each(mm.begin(), mm.end(), &show);
cout << endl;
//map::iterator ite4 = mm.lower_bound("UU"); //返回大于等于该键值的迭代器 有UU 返回UU
map<string, int>::iterator ite4 = mm.lower_bound("EE"); //返回大于等于该键值的迭代器 没有EE 返回EE后面的有的键值 此处有CC DD UU SS PP 所以返回PP
cout << ite4->first << " " << ite4->second << endl;
cout << endl;
map<string, int>::iterator ite5 = mm.upper_bound("PP"); //返回大于该键值的迭代器 CC DD PP SS UU 所以此处返回SS
cout << ite5->first << " " << ite5->second << endl;
cout << endl;
mm["SS"] = 5000;
::for_each(mm.begin(), mm.end(), &show);
cout << endl;
map<string, int>::iterator ite6 = mm.find("SS");
//ite6->first = "MM"; //不可以改键值!!只可以改实值!!
ite6->second = 1;
::for_each(mm.begin(), mm.end(), &show);
}
容器查阅文档见下:
sequence序列容器
list
vector
deque
associative关联容器
map
set
容器-迭代器-算法 ——关系表
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)