目录
一、 模板
模板可以让类或者函数支持一种通用类型,这种通用数据类型在实际运行的过程中可以使用任何数据类型。因此程序员可以写出一些与类型无关的代码,这种编程方式也被称为泛型编程。
通常有两种实现形式:
● 函数模板
● 类模板
1 .函数模板
使一个函数支持模板编程,可以使函数支持通用数据类型。
#include <iostream>
using namespace std;
template<typename T> // typename 也可以是class
T add(T a,T b)
{
return a+b;
}
int main()
{
string a = "hello";
string b = "world";
cout << add(a,b);
return 0;
}
2 .类模板
使一个类支持模板编程,可以使一个类支持通用数据类型。
#include <iostream>
using namespace std;
template<typename T> // typename 也可以是class
int add(int a,int b)
{
return a+b;
}
// 类模板
template<class T>
class Test
{
private:
T val;
public:
Test(T v);
T get_val();
void set_val(const T &val);
};
template<class T>
Test<T>::Test(T v):val(v)
{
}
template<class T>
T Test<T>::get_val()
{
return val;
}
template<class T>
void Test<T>::set_val(const T &val)
{
this->val = val;
}
int main()
{
Test<int> t1(20);
cout << t1.get_val() << endl;
Test<double> t2(3.14);
cout << t2.get_val() << endl;
Test<string> t3("hello");
cout << t3.get_val() << endl;
return 0;
}
二、容器
1 .标准模板库STL
标准模板库(Standard Template Library,STL)是惠普实验室开发的一系列软件的统称。虽说它主要出现到了C++中,但是在被引入C++之前该技术就已经存在了很长时间。
STL的代码从广义上讲分为三类:algorithm(算法)、container(容器)和iterator(迭代器),几乎所有的代码都采用了模板类和模板函数的方式,这相比于传统的由函数和类组成的库来说提供了更好的代码重用机会。
2. 概念
容器是用来存储数据的集合,数据的元素可以是任何类型(因为是使用模板实现)。
容器类的使用,都需要引入对应的头文件。
3 顺序容器
顺序容器中每个元素均有固定的位置并程线行排布。除非使用删除或者插入的操作改变元素的位置。否则元素位置不变。
3.1 array数组
array数组是C++11新增的容器类型,与传统数组相比更加安全、更加易于使用。array数组是定长的,没办法方便进行伸缩。
#include <iostream>
#include <array>
using namespace std;
int main()
{
// 创建一个长度为5的int数组
array<int,5> arr = {1,2,3}; // 后面两位补零
cout << arr[0] << endl; // 1
cout << arr[4] << endl; // 0
cout << arr.at(2) << endl; // 3
arr[3] = 200;
// for循环
for(int i = 0;i < arr.size();++i)
{
cout << arr[i] << endl;
}
// for each
for(int i : arr)
{
cout << i << endl;
}
// 迭代器遍历,后面说
return 0;
}
2.3.2 vector 向量
vector内部是由数组实现的,比较适合进行随机存取操作,而不擅长插入和删除操作。
#include <iostream>
#include <vector>
using namespace std;
int main()
{
// vector<int> v = {1,2,3};
// cout << v.size() << endl;
// for(int i:v)
// {
// cout << i << endl;
// }
// 创建一个长度为5的int向量
vector<int> vec(5);
cout << vec.size() << endl; // 5
// 增
vec.push_back(222);
cout << vec.size() << endl; // 6
// +2是在第三个位置上插入333
vec.insert(vec.begin()+2,333); // begin()可以返回指向第一个元素的迭代器指针
// 改
vec.at(0) = 1;
vec[1] = 2;
vec[3] = 4;
vec[4] = 5;
// 删除
// 删除最后一个元素
vec.pop_back();
// // 删除第二个元素
vec.erase(vec.begin()+1);
vec.erase(vec.end()-2); // 删除倒数第二个元素
// 查
// 取出单个元素
cout << vec[0] << endl;
cout << vec.at(2) << endl;
// 遍历
for(int i = 0; i < vec.size() ;++i)
{
cout << vec[i] << " ";
}
cout << endl;
for(int i:vec)
{
cout << i <<" ";
}
cout << endl;
// 迭代器遍历,先省略
// 判断是否空,0非空,1空
cout << vec.empty() << endl;
// 清空
vec.clear();
cout << vec.empty() << endl; // 1
return 0;
}
3.3 list列表
list内部是由双向循环链表实现,内存空间不连续,不支持下标访问。优点:可以高效的删除和插入操作。但是不适合随机存取操作。
#include <iostream>
#include <list>
using namespace std;
int main()
{
// 创建一个默认无数值的list
// list<string>lis1;
// // 创建一个长度为2的列表,第一个元素是hello第二个元素是world
// list<string>lis2{"hello","world"};
// for(string s :lis2)
// {
// cout << s << endl;
// }
// 创建一个长度为5的列表,每个元素都是"hello"
list<string>lis(5,"hello");
// 增
lis.push_back("world"); // 向后追加单元素
lis.push_front("hahaha"); // 向前追加单元素
lis.insert(++lis.begin(),"222"); // 在第二个位置上插入“222”
// 删
// lis.pop_back(); // 删除最后一个元素
lis.pop_front(); // 删除第一个元素
// 保存迭代器指针
list<string>::iterator iter = lis.begin();
advance(iter,1); // 移动迭代器指针
lis.insert(iter,"333");
// 删除 最后一个元素
// iter = lis.end();
// iter--;
// lis.erase(iter);
iter = lis.begin();
advance(iter,1);
lis.erase(iter);
// 返回第一个元素的引用
// cout << lis.front() << endl;
// 最后一个元素的引用
// cout << lis.back() << endl;
// 改
iter = lis.end();
advance(iter,2);
*iter = "200";
// 查
cout << *iter << endl;
// 遍历 for each
for(string s :lis)
{
cout << s << endl;
}
// 迭代器遍历,后面说
// 清空
lis.clear();
cout << lis.size() << endl;
return 0;
}
3.4 deque队列
队列几乎支持所有vector的API,性能位于vector与list两者之间。是最擅长两端存取的顺序容器。
#include <iostream>
#include <deque>
using namespace std;
int main()
{
// deque<int> v = {1,2,3};
// cout << v.size() << endl;
// for(int i:v)
// {
// cout << i << endl;
// }
// 创建一个长度为5的int向量
deque<int> deq(5);
cout << deq.size() << endl; // 5
// 增
deq.push_back(222);
cout << deq.size() << endl; // 6
// +2是在第三个位置上插入333
deq.insert(deq.begin()+2,333); // begin()可以返回指向第一个元素的迭代器指针
// 改
deq.at(0) = 1;
deq[1] = 2;
deq[3] = 4;
deq[4] = 5;
// 删除
// 删除最后一个元素
deq.pop_back();
// // 删除第二个元素
deq.erase(deq.begin()+1);
deq.erase(deq.end()-2); // 删除倒数第二个元素
// 查
// 取出单个元素
cout << deq[0] << endl;
cout << deq.at(2) << endl;
// 遍历
for(int i = 0; i < deq.size() ;++i)
{
cout << deq[i] << " ";
}
cout << endl;
for(int i:deq)
{
cout << i <<" ";
}
cout << endl;
// 迭代器遍历,先省略
// 判断是否空,0非空,1空
cout << deq.empty() << endl;
// 清空
deq.clear();
cout << deq.empty() << endl; // 1
return 0;
}
4 关联容器
关联容器的各个元素之间没有严格顺序,虽然内部具有排序的特点,但是在使用时没有任何顺序相关的接口。
最常见的关联容器map-键值对映射。
对于map而言,键具有唯一性,键通常使用字符串类型,值可能是任何类型。通过键可以找到对应的值。
#include <iostream>
#include <map>
using namespace std;
int main()
{
map<string,int>ma1 = {{"身高",190},{"体重",250}}; // 有两个元素
cout << ma1.size() << endl; // 2
// 创建一个元素数据为0的键值对对象
map<string,int>ma;
cout << ma.size() << endl; // 0
// 增
ma["身高"] = 180;
ma.insert(pair<string,int>("体重",150)); // 插入元素
// 改
ma["身高"] = 110; // 修改元素
cout << ma.size() << endl;
// 查
cout << ma["身高"] << endl;
cout << ma["体重"] << endl;
if(ma.find("身高") == ma.end()) // find从头开始查找,如果没找到返回end
{
cout << "没有找到身高元素" << endl;
}
else
{
cout << ma["身高"] << endl;
}
// 删
int re = ma.erase("身高"); // 返回值1表示删除成功,0失败
cout << "身高删除:" << re << endl;
cout << ma.size() << endl; // 1
re = ma.erase("月薪");
cout << "删除:" << re << endl;
ma.clear();
cout << ma.size() << endl; // 0
return 0;
}
5 迭代器遍历
迭代器是一个特殊的指针,主要用于容器元素的读写以及遍历。
如果迭代器不进行修改,建议使用只读迭代器:const_iterator,反之则使用iterator。
#include <iostream>
#include <map>
#include <array>
#include <vector>
#include <list>
#include <deque>
using namespace std;
int main()
{
string s = "abcdefg";
// 迭代器遍历string
for(string::const_iterator iter = s.begin(); iter != s.end(); iter++)
{
cout << *iter << " ";
}
cout << endl;
cout << "--------------------" << endl;
// 迭代器遍历array
array<int,5> arr = {5,3,6,333,7};
for(array<int,5>::const_iterator iter = arr.begin(); iter != arr.end();iter++)
{
cout << *iter << " ";
}
cout << endl;
cout << "--------------------" << endl;
// 迭代器遍历vector
vector<string> vec(6,"hello");
for(vector<string>::const_iterator iter = vec.begin(); iter != vec.end(); iter++)
{
cout << *iter << " ";
}
cout << endl;
cout << "--------------------" << endl;
// 迭代器遍历list
list<string>lis(6,"world");
for(list<string>::const_iterator iter = lis.begin(); iter != lis.end();++iter)
{
cout << *iter << " ";
}
cout << endl;
cout << "--------------------" << endl;
// 迭代器遍历队列
deque<string> deq(6,"haha");
for(deque<string>::iterator iter = deq.begin(); iter != deq.end();++iter)
{
*iter = "heiheihei";
cout << *iter << " ";
}
cout << endl;
cout << "--------------------" << endl;
// 迭代器遍历map
map<string,int>ma;
ma["年龄"] = 24;
ma["身高"] = 180;
ma["体重"] = 140;
for(map<string,int>::const_iterator iter = ma.begin();iter != ma.end();iter++)
{
// first 是键 second 是值
cout << iter->first << " " << iter->second << endl;
}
return 0;
}