这里写自定义目录标题
vector容器
1.vector基本概念
//功能:
//vector数据结构和数组非常相似,也称为单端数组
//vector与普通数组区别:
//不同之处在于数组是静态空间,而vector可以动态扩展
//静态空间容量是一定的,不能再扩展,比如原来有5个容量,那就只能装5个数
//动态扩展:
//并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝新空间,释放原空间
//vector容器的迭代器是支持随机访问的迭代器
2.vector构造函数
//功能描述:
//创建vector容器
//函数原型:
//vector<T> v;//采用模板实现类实现,默认构造函数
//vector(v.begin(), v.end());//将v[begin(), end())区间中的元素拷贝给本身。 注意是前闭后开区间
//vector(n, elem);//构造函数将n个elem拷贝给本身。
//vector(const vector &vec);//拷贝构造函数。
//总结:vector的多种构造方式没有可比性,灵活使用即可
代码:
/*vector构造函数*/
//功能描述:
//创建vector容器
//函数原型:
//vector<T> v;//采用模板实现类实现,默认构造函数
//vector(v.begin(), v.end());//将v[begin(), end())区间中的元素拷贝给本身。 注意是前闭后开区间
//vector(n, elem);//构造函数将n个elem拷贝给本身。
//vector(const vector &vec);//拷贝构造函数。
void printVector(vector<int> &v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test37()
{
vector<int>v1;//默认构造 无参构造
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
//通过区间方式进行构造
vector<int> v2(v1.begin(), v1.end());
printVector(v2);
//n个elem方式构造
vector<int>v3(10, 100);
printVector(v3);
//拷贝构造
vector<int>v4(v3);
printVector(v4);
}
//总结:vector的多种构造方式没有可比性,灵活使用即可
main函数:
/*vector构造函数*/
test37();
3.vector赋值操作
//功能描述:
//给vector容器进行赋值
//函数原型:
//vector& operator=(const vector &vec); //重载等号操作符
//assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。注意是前闭后开
//assign(n, elem);//将n个elem拷贝赋值给本身。
//总结: vector赋值方式比较简单,使用operator=,或者assign都可以
代码:
/*vector赋值操作*/
//功能描述:
//给vector容器进行赋值
//函数原型:
//vector& operator=(const vector &vec); //重载等号操作符
//assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。注意是前闭后开
//assign(n, elem);//将n个elem拷贝赋值给本身。
void test38()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
cout << "------------" << endl;
//等号赋值
vector<int>v2;
v2 = v1;
printVector(v2);
cout << "---------------" << endl;
//assign
vector<int>v3;
v3.assign(v1.begin(), v1.end());
printVector(v3);
cout << "---------------" << endl;
//n个elem方式
vector<int>v4;
v4.assign(10, 100);
printVector(v4);
cout << "---------------" << endl;
}
//总结: vector赋值方式比较简单,使用operator=,或者assign都可以
main函数:
/*vector赋值操作*/
test38();
4.vector容量和大小
//功能描述:
//对vector容器的容量和大小操作
//函数原型:
//empty(); //判断容器是否为空
//capacity(); //容器的容量 容量capacity要≥size
//size(); //返回容器中元素的个数
//resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值0填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
//resize(int num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除
//总结:
//判断是否为空-- - empty
//返回元素个数-- - size
//返回容器容量-- - capacity
//重新指定大小-- - resize
代码:
/*vector容量和大小*/
//功能描述:
//对vector容器的容量和大小操作
//函数原型:
//empty(); //判断容器是否为空
//capacity(); //容器的容量 容量capacity要≥size
//size(); //返回容器中元素的个数
//resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值0填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
//resize(int num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除
void test39()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
if (v1.empty())//为真代表容器为空
{
cout << "v1为空" << endl;
}
else
{
cout << "v1不为空" << endl;
cout << "v1的容量为:" << v1.capacity() << endl;
cout << "v1的大小为:" << v1.size() << endl;
}
v1.resize(15);//如果重新指定比原来的长了,默认用0来填充
printVector(v1);
v1.resize(5);//比原来短了去掉后面的
printVector(v1);
v1.resize(16, 100);//也可以指定填充的数据
printVector(v1);
}
//总结:
//判断是否为空-- - empty
//返回元素个数-- - size
//返回容器容量-- - capacity
//重新指定大小-- - resize
main函数:
/*vector容量和大小*/
test39();
5.vector插入和删除
//功能描述:
//对vector容器进行插入、删除操作
//函数原型:
//push_back(ele);//尾部插入元素ele
//pop_back(); //删除后一个元素
//insert(const_iterator pos, ele); //迭代器指向位置pos插入元素ele
//insert(const_iterator pos, int count,ele); //迭代器指向位置pos插入count个元素ele
//erase(const_iterator pos);//删除迭代器指向的元素
//erase(const_iterator start, const_iterator end); //删除迭代器从start到end之间的元素
//clear();//删除容器中所有元素
//总结:
//尾插 --- push_back
//尾删 --- pop_back
//插入 --- insert(位置迭代器)
//删除 --- erase(位置迭代器)
//清空 --- clear
代码:
/*vector插入和删除*/
//功能描述:
//对vector容器进行插入、删除操作
//函数原型:
//push_back(ele);//尾部插入元素ele
//pop_back(); //删除后一个元素
//insert(const_iterator pos, ele); //迭代器指向位置pos插入元素ele
//insert(const_iterator pos, int count,ele); //迭代器指向位置pos插入count个元素ele
//erase(const_iterator pos);//删除迭代器指向的元素
//erase(const_iterator start, const_iterator end); //删除迭代器从start到end之间的元素
//clear();//删除容器中所有元素
void test40()
{
vector<int>v1;
//尾插
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(50);
//遍历
printVector(v1);
//尾删
v1.pop_back();
printVector(v1);
//插入 第一个参数是迭代器
v1.insert(v1.begin(), 100);
printVector(v1);
v1.insert(v1.begin(), 2, 1000);
printVector(v1);
//删除 参数也是迭代器
v1.erase(v1.begin());
printVector(v1);
//v1.erase(v1.begin(), v1.end());//全部删除相当于清空
//printVector(v1);
//清空
v1.clear();
printVector(v1);
}
//总结:
//尾插 --- push_back
//尾删 --- pop_back
//插入 --- insert(位置迭代器)
//删除 --- erase(位置迭代器)
//清空 --- clear
main函数:
/*vector插入和删除*/
test40();
6.vector数据存取
//功能描述:
//对vector中的数据的存取操作
//函数原型:
//at(int idx);//返回索引idx所指的数据
//operator[];//返回索引idx所指的数据
//front();//返回容器中第一个数据元素
//back();//返回容器中后一个数据元素
//总结:
//除了用迭代器获取vector容器中元素,[]和at也可以
//front返回容器第一个元素
//back返回容器后一个元素
代码:
/*vector数据存取*/
//功能描述:
//对vector中的数据的存取操作
//函数原型:
//at(int idx);//返回索引idx所指的数据
//operator[];//返回索引idx所指的数据
//front();//返回容器中第一个数据元素
//back();//返回容器中后一个数据元素
void test41()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
for (int i = 0; i < v1.size(); i++)
{
//利用[]
cout << v1[i] << " ";
//利用at
cout << v1.at(i) << " ";
}
cout << endl;
//第一个元素
cout << v1.front() << endl;
//最后一个元素
cout << v1.back() << endl;
}
//总结:
//除了用迭代器获取vector容器中元素,[]和at也可以
//front返回容器第一个元素
//back返回容器后一个元素
main函数:
/*vector数据存取*/
test41();
7.vector互换容器
//功能描述:
//实现两个容器内元素进行互换
//函数原型:
//swap(vec); // 将vec与本身的元素互换
//总结:swap可以使两个容器互换,可以达到实用的收缩内存效果
//巧用swap收缩内存
//vector<int>(v1).swap(v1);
代码:
/*vector互换容器*/
//功能描述:
//实现两个容器内元素进行互换
//函数原型:
//swap(vec); // 将vec与本身的元素互换
void test42()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
vector<int>v2;
for (int i = 10; i > 0; i--)
{
v2.push_back(i);
}
printVector(v2);
cout << "------------" << endl;
v1.swap(v2);
printVector(v1);
printVector(v2);
}
//实际用途
//巧用swap可以收缩内存空间
void test43()
{
vector<int>v1;
for (int i = 0; i < 100000; i++)
{
v1.push_back(i);
}
cout << "v1的容量为:" << v1.capacity() << endl;
cout << "v1的大小为:" << v1.size() << endl;
v1.resize(3);
cout << "v1的容量为:" << v1.capacity() << endl;
cout << "v1的大小为:" << v1.size() << endl;
//巧用swap收缩内存
vector<int>(v1).swap(v1);
cout << "v1的容量为:" << v1.capacity() << endl;
cout << "v1的大小为:" << v1.size() << endl;
}
//总结:swap可以使两个容器互换,可以达到实用的收缩内存效果
//巧用swap收缩内存
//vector<int>(v1).swap(v1);
main函数:
/*vector互换容器*/
test42();
test43();
8.vector预留空间
//功能描述:
//减少vector在动态扩展容量时的扩展次数
//函数原型:
//reserve(int len); //容器预留len个元素长度,预留位置不初始化,元素不可访问
if (p != &v1[0])//如果不等于首地址
{
p = &v1[0];//重新开辟内存的时候,首地址发生变化
num++;
}
//总结:如果数据量较大,可以一开始利用reserve预留空间
代码:
/*vector预留空间*/
//功能描述:
//减少vector在动态扩展容量时的扩展次数
//函数原型:
//reserve(int len); //容器预留len个元素长度,预留位置不初始化,元素不可访问
void test44()
{
vector<int>v1;
//利用reserve预留空间
v1.reserve(100000);
//统计开辟次数
int num = 0;
int *p = NULL;
for (int i = 0; i < 100000; i++)
{
v1.push_back(i);
if (p != &v1[0])//如果不等于首地址
{
p = &v1[0];//重新开辟内存的时候,首地址发生变化
num++;
}
}
cout << "num=" << num << endl;
}
//总结:如果数据量较大,可以一开始利用reserve预留空间
main函数:
/*vector预留空间*/
test44();
代码
#include<iostream>
#include<string>
//第一种解决方式,直接包含源文件
//因为类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到
//#include"Person_fwj.cpp"
//第二种解决方式,将.h和.cpp中的内容写到一起,将后缀名改为.hpp文件
#include "Person_fwj.hpp"
#include"MyArry.hpp"
#include<vector>
#include<algorithm>
using namespace::std;
/*函数模板*/
//C++另一种编程思想称为泛型编程,主要利用模板技术
//C++提供两种模板机制:函数模板和类模板
/*函数模板语法*/
//函数模板作用:
//建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型来代表。
//语法:
//template<typename T>
//函数声明或定义
//template--声明创建模板
//typename--表明其后面的符号是一种数据类型,可以用class代替
//T--通用的数据类型,名称可以替换,通常为大写字母
//交换两个整型的函数
void swapInt(int &a, int &b)
{
int temp = a;
a = b;
b = temp;
}
//交换两个浮点型函数
void swapDouble(double &a, double &b)
{
double temp = a;
a = b;
b = temp;
}
//函数模板
template<typename T> //声明一个模板,告诉编译器后面代码中紧跟着的T不要报错,T是一个通用数据类型
void mySwap(T &a, T &b)
{
T temp = a;
a = b;
b = temp;
}
void test01()
{
int a = 10;
int b = 20;
//swapInt(a, b);
//利用函数模板交换
//两种方式使用函数模板
//1.自动类型推导
mySwap(a, b);//自己推出是整型
//2显示指定类型
mySwap<int>(a, b);//通过<int>指定是整型
cout << "a=" << a << "\tb=" << b << endl;
double c = 1.1;
double d = 1.2;
swapDouble(c, d);
cout << "c=" << c << "\td=" << d << endl;
/*函数模板注意事项*/
//1.自动类型推导,必须推导出一致的数据类型T,才可以使用
//2.模板必须要确定出T的数据类型,才可以使用
//mySwap(a, c); //错误,推导不出一致的T类型,因为c是double
}
//模板必须要确定出T的数据类型,才可以使用
template<typename T>
void func01()
{
cout << "func的调用" << endl;
}
void test02()
{
//func01;//错误,模板不能独立使用,必须确定出T的类型
func01<int>();//正确,利用显示指定类型的方式,给T一个类型,才可以使用该模板
}
//总结:使用模板时必须确定出通用数据类型T,并且能够推导出一致的类型
/*函数模板案例*/
//案例描述:
//利用函数模板封装一个排序的函数,可以对不同数据类型数组进行排序
//排序规则从大到小,排序算法为选择排序
//分别利用char数组和int数组进行测试
//交换函数模板
template<typename T>
void mySwap2(T &a, T &b)
{
T temp = a;
a = b;
b = temp;
}
//排序算法--选择排序
template<typename T>
void mySort(T arr[], int len)
{
for (int i = 0; i < len; i++)
{
int max = i;//认定最大值的下标
for (int j = i + 1; j < len; j++)
{
//认定的最大值比遍历出的数值要小,说明j下标的元素才是真正的最大值
if (arr[max] < arr[j])
{
max = j;
}
}
if (max != i)
{
//交换max和i元素
mySwap2(arr[max], arr[i]);
}
}
}
//提供打印数组模板
template<typename T>
void printArry(T arr[],int len)
{
for (int i = 0; i < len; i++)
{
cout << arr[i] << " ";
cout << endl;
}
}
void test03()
{
//测试char数组
char charARR[] = "bacdfe";
mySort(charARR, sizeof(charARR) / sizeof(char));
printArry(charARR, sizeof(charARR) / sizeof(char));
//测试int数组
int intArr[] = { 1,5,4,3,6,2,7,0 };
mySort(intArr, sizeof(intArr) / sizeof(int));
printArry(intArr, sizeof(intArr) / sizeof(int));
}
/*普通函数与函数模板的区别*/
//区别
//1.普通函数调用时可以发生自动类型转换(隐式类型转换)
//2.函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
//3.如果利用显示指定类型的方式,可以发生隐式类型转换
//普通函数
int myAdd01(int a, int b)
{
return a + b;
}
//函数模板
template<typename T>
T myAdd02(T a, T b)
{
return a + b;
}
void test04()
{
int a = 10;
int b = 20;
char c = 'c';
cout << myAdd01(a, b) << endl;
cout << myAdd01(a, c) << endl;//正确,将char类型的'c'隐式转换为int类型 'c' 对应 ASCII码 99
cout << myAdd02(a, b) << endl;
//cout << myAdd02(a, c) << endl;//报错,使用自动类型推导时,不会发生隐式类型转换
cout << myAdd02<int>(a, c) << endl;//正确,如果用显示指定类型,可以发生隐式类型转换
}
//总结:建议使用显示指定类型的方式,调用函数模板,因为可以自己确定通用类型
/*普通函数与函数模板的调用规则*/
//调用规则如下:
//1.如果函数模板和普通函数都可以实现,优先调用普通函数
//2.可以通过空模板参数列表来强制调用函数模板
//3.函数模板也可以发生重载
//4.如果函数模板可以产生更好地匹配,优先调用函数模板
void myPrint(int a, int b)
{
cout << "调用的普通函数" << endl;
}
template<typename T>
void myPrint(T a, T b)
{
cout << "调用的模板函数" << endl;
}
//函数模板重载
template<typename T>
void myPrint(T a, T b, T c)
{
cout << "调用的重载模板函数" << endl;
}
void test05()
{
int a = 10;
int b = 10;
myPrint(a, b);
//通过空模板参数列表,强制调用函数模板
myPrint<>(a, b);
//模板重载
myPrint(a, b, 100);
//如果函数模板产生更好地匹配,优先调用函数模板
char c1 = 'a';
char c2 = 'b';
myPrint(c1, c2);//调用函数模板,因为如果调用普通函数还得进行类型转换,所以编译器为了省事直接调用模板函数
}
//总结:既然提供了函数模板,好就不要提供普通函数,否则容易出现二义性
/*模板的局限性*/
//模板并不是万能的,有些特定数据类型,需要用具体方式特殊实现
class Person_jx
{
public:
Person_jx(string name, int age)
{
this->m_Age = age;
this->m_Name = name;
}
public:
int m_Age;
string m_Name;
};
//对比两个数据是否相等函数
template<typename T>
bool myCompare(T &a, T &b)
{
if (a == b)
{
return true;
}
else
{
return false;
}
}
//利用具体化Person的版本来实现代码,具体化优先调用
template<>bool myCompare(Person_jx &p1, Person_jx &p2)
{
if (p1.m_Name == p2.m_Name&&p1.m_Age == p2.m_Age)
{
return true;
}
else
{
return false;
}
}
void test06()
{
int a = 10;
int b = 20;
bool result = myCompare(a, b);
if (result)
{
cout << "a=b" << endl;
}
else
{
cout << "a!=b" << endl;
}
}
void test07()
{
Person_jx p1("Tom", 10);
Person_jx p2("Tom", 10);
bool result = myCompare(p1, p2);
if (result)
{
cout << "p1=p2" << endl;
}
else
{
cout << "p1!=p2" << endl;
}
}
//总结:
//利用具体化的模板,可以解决自定义类型的通用化
//学习模板并不是为了写模板,而是在STL能够运用系统提供的模板
/*类模板语法*/
//语法:template<class 形参1, class 形参2...>
//类
template<class NameType,class AgeType>
class Person_lmb
{
public:
Person_lmb(NameType name, AgeType age)//这里不能传引用,要不然实例化会报错
{
this->m_Age = age;
this->m_Name = name;
}
void showPerson_lmb()
{
cout << "姓名:" << this->m_Age << "\t年龄:" << this->m_Age << endl;
}
public:
NameType m_Name;
AgeType m_Age;
};
void test08()
{
Person_lmb<string, int> p1("Tom", 18);
p1.showPerson_lmb();
}
/*类模板与函数模板区别*/
//类模板与函数模板区别主要有两点:
//1. 类模板没有自动类型推导的使用方式
//2. 类模板在模板参数列表中可以有默认参数
template<class NameType, class AgeType=int>//可以有默认参数
class Person_qv
{
public:
Person_qv(NameType name, AgeType age)
{
this->m_Name = name;
this->m_Age = age;
}
void showPerson_qv()
{
cout << "姓名:" << this->m_Name << "\t年龄:" << this->m_Age << endl;
}
public:
NameType m_Name;
AgeType m_Age;
};
//1.类模板没有自动类型推导使用方式
void test09()
{
//Person_qv p("Tom", 200);//错误,无法自动类型推导
Person_qv<string, int> p("Tom", 200);//正确,需要指定显示类型
p.showPerson_qv();
}
//2.类模板在模板参数列表中可以有默认参数
void test10()
{
Person_qv<string> p("Simi", 1000);
p.showPerson_qv();
}
/*类模板中成员函数创建时机*/
//类模板中成员函数和普通类中成员函数创建时机是有区别的:
//普通类中的成员函数一开始就可以创建
//类模板中的成员函数在调用时才创建
class Person_sj1
{
public:
void showPerson_sj1()
{
cout << "Person_sj1 show" << endl;
}
public:
};
class Person_sj2
{
public:
void showPerson_sj2()
{
cout << "Person_sj2 show" << endl;
}
public:
};
template <class T>
class myClass_sj
{
public:
//类模板中的成员函数
void func1()
{
obj.showPerson_sj1();
}
void func2()
{
obj.showPerson_sj2();
}
public:
T obj;
};
void test11()
{
myClass_sj<Person_sj2> m;
//m.func1();
m.func2();
}
//总结:类模板中的成员函数并不是一开始就创建的,在调用时才去创建
/*类模板对象做函数参数*/
//学习目标:
//类模板实例化出的对象,向函数传参的方式
//一共有三种传入方式:
//1. 指定传入的类型-- - 直接显示对象的数据类型
//2. 参数模板化-- - 将对象中的参数变为模板进行传递
//3. 整个类模板化-- - 将这个对象类型 模板化进行传递
template<class T1,class T2>
class Person_hx
{
public:
Person_hx(T1 name, T2 age)
{
this->m_Age = age;
this->m_Name = name;
}
void showPerson()
{
cout << "姓名:" << this->m_Name << "\t年龄:" << this->m_Age << endl;
}
public:
T1 m_Name;
T2 m_Age;
};
//1.指定传入类型
void printPerson1(Person_hx<string, int> &p)
{
p.showPerson();
}
void test12()
{
Person_hx<string, int> p("Tom", 100);
printPerson1(p);
}
//参数模板化
//看数据类型用typeid(变量名).name()
template<class T1, class T2>
void printPerson2(Person_hx<T1,T2> &p)
{
p.showPerson();
cout << "T1的类型为:" << typeid(T1).name() << endl;
cout << "T2的类型为:" << typeid(T2).name() << endl;
}
void test13()
{
Person_hx<string, int> p("SImi", 200);
printPerson2(p);
}
//3.整个类模板化
template<class T>
void printPerson3(T & p)
{
p.showPerson();
cout << "T的数据类型:" << typeid(T).name() << endl;
}
void test14()
{
Person_hx<string, int>p("Jier", 400);
printPerson3(p);
}
//总结:
//通过类模板创建的对象,可以有三种方式向函数中进行传参
//使用比较广泛是第一种:指定传入的类
/*类模板与继承*/
//当类模板碰到继承时,需要注意一下几点:
//当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
//如果不指定,编译器无法给子类分配内存
//如果想灵活指定出父类中T的类型,子类也需变为类模板
template<class T>
class Base1
{
public:
public:
T m;
};
//class Son1 :public Base1//错误的,必须要知道父类中的T类型,才能继承给子类
class Son1:public Base1<int>
{
public:
public:
};
void test15()
{
Son1 s;
}
//如果想灵活指定父类中T类型,子类也需要变类模板
template<class T1,class T2>
class Son2 :public Base1<T2>
{
public:
Son2()
{
cout << "T1的数据类型为:" << typeid(T1).name() << "\tT2的数据类型为:" << typeid(T2).name() << endl;
}
public:
T1 obj;
};
void test16()
{
Son2<int, char>s2;//int传给T1,char传给T2,T2也就是父类的数据类型
}
//总结:如果父类是类模板,子类需要指定出父类中T的数据类型
/*类模板成员函数类外实现*/
template <class T1,class T2>
class Person_sx
{
public:
Person_sx(T1 name, T2 age);
//{
// this->m_Age = age;
// this->m_Name = name;
//}
void showPerson();
//{
// cout << "姓名:" << this->m_Name << "\t年龄:" << this->m_Age << endl;
//}
public:
T1 m_Name;
T2 m_Age;
};
//构造函数类外实现
template<class T1,class T2>
Person_sx<T1,T2>::Person_sx(T1 name, T2 age)//在::前加<T1,T2>
{
this->m_Age = age;
this->m_Name = name;
}
//成员函数类外实现
template<class T1,class T2>
void Person_sx<T1, T2>::showPerson()//在::前加<T1,T2>
{
cout << "姓名:" << this->m_Name << "\t年龄:" << this->m_Age << endl;
}
void test17()
{
Person_sx<string, int> p("Tom", 100);
p.showPerson();
}
//总结:类模板中成员函数类外实现时,需要加上模板参数列表
/*类模板分文件编写*/
//问题:
//类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到
//解决:
//解决方式1:直接包含.cpp源文件
//解决方式2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制
//template <class T1, class T2>
//class Person_fwj
//{
//public:
// Person_fwj(T1 name, T2 age);
//
// void showPerson();
//
//public:
// T1 m_Name;
// T2 m_Age;
//};
//template <class T1, class T2>
//Person_fwj<T1, T2>::Person_fwj(T1 name, T2 age)
//{
// this->m_Name = name;
// this->m_Age = age;
//}
//
//template <class T1, class T2>
//void Person_fwj<T1, T2>::showPerson()
//{
// cout << "姓名:" << this->m_Name << "\t年龄:" << this->m_Age << endl;
//}
void test18()
{
Person_fwj<string, int>p("Jerry", 18);
p.showPerson();
}
/*类模板与友元*/
//全局函数类内实现 - 直接在类内声明友元即可
//全局函数类外实现 - 需要提前让编译器知道全局函数的存在
//类外实现
//如果全局函数是类外实现,需要让编译器提前知道这个函数的存在
//提前让编译器知道Person类的存在
template<class T1, class T2>
class Person_yy;
template<class T1, class T2>
void printPerson_yy2(Person_yy<T1, T2>p)
{
cout << "类外实现 姓名:" << p.m_Name << "\t年龄:" << p.m_Age << endl;
}
template <class T1, class T2>
class Person_yy
{
//全局函数类内实现
friend void printPerson_yy(Person_yy<T1, T2>p)
{
cout << "姓名:" << p.m_Name << "\t年龄:" << p.m_Age << endl;
}
//全局函数类外实现
//加空模板参数列表<>
//如果全局函数是类外实现,需要让编译器提前知道这个函数的存在
friend void printPerson_yy2<>(Person_yy<T1, T2>p);
public:
Person_yy ( T1 name, T2 age)
{
this->m_Age = age;
this->m_Name = name;
}
private:
T1 m_Name;
T2 m_Age;
};
//全局函数在类内实现调用
void test19()
{
Person_yy<string, int> p("Hello", 120);
printPerson_yy(p);
}
//全局函数在类外实现调用
void test20()
{
Person_yy<string, int>p("Giao", 20);
printPerson_yy2(p);
}
//总结:建议全局函数做类内实现,用法简单,而且编译器可以直接识别
/*类模板案例*/
//案例描述: 实现一个通用的数组类,要求如下:
//可以对内置数据类型以及自定义数据类型的数据进行存储
//将数组中的数据存储到堆区
//构造函数中可以传入数组的容量
//提供对应的拷贝构造函数以及operator = 防止浅拷贝问题
//提供尾插法和尾删法对数组中的数据进行增加和删除
//可以通过下标的方式访问数组中的元素
//可以获取数组中当前元素个数和数组的容量
void printArray(MyArray<int> &arr)
{
for (int i = 0; i < arr.getSize(); i++)
{
cout << arr[i] << endl;
}
}
void test21()
{
MyArray<int> arr1(5);
for (int i = 0; i < 5; i++)
{
//利用尾插法向数组中插入数据
arr1.PushBack(i);
}
cout << "arr1的打印输出:" << endl;
printArray(arr1);
cout << "arr1的容量:" << arr1.getCapacity() << endl;
cout << "arr1的大小:" << arr1.getSize() << endl;
MyArray<int>arr2(arr1);
cout << "arr2的打印输出:" << endl;
printArray(arr2);
//尾删
arr2.PopBack();
cout << "arr2的容量:" << arr2.getCapacity() << endl;
cout << "arr2的大小:" << arr2.getSize() << endl;
MyArray<int>arr3(100);
arr3 = arr1;
}
//测试自定义数据类型
class Person_zdy
{
public:
Person_zdy()
{
}
Person_zdy(string name, int age)
{
this->m_Age = age;
this->m_Name = name;
}
public:
string m_Name;
int m_Age;
};
void printPersonArray(MyArray<Person_zdy> &arr)
{
for (int i = 0; i < arr.getSize(); i++)
{
cout << "姓名:" << arr[i].m_Name << "\t年龄:" << arr[i].m_Age << endl;
}
}
void test22()
{
MyArray<Person_zdy> arr(10);
Person_zdy p1("Tom", 11);
Person_zdy p2("Simi", 12);
Person_zdy p3("REm", 13);
Person_zdy p4("DFDm", 14);
Person_zdy p5("SAGm", 15);
//将数据插入到数组中
arr.PushBack(p1);
arr.PushBack(p2);
arr.PushBack(p3);
arr.PushBack(p4);
arr.PushBack(p5);
//打印数组
printPersonArray(arr);
//输出容量
cout << "arr的容量为:" << arr.getCapacity() << endl;
//输出大小
cout << "arr的大小为:" << arr.getSize() << endl;
}
/*STL的诞生*/
//长久以来,软件界一直希望建立一种可重复利用的东西
//C++的面向对象和泛型编程思想,目的就是复用性的提升
//大多情况下,数据结构和算法都未能有一套标准,导致被迫从事大量重复工作
//为了建立数据结构和算法的一套标准,诞生了ST
/*STL基本概念*/
//STL(Standard Template Library,标准模板库)
//STL 从广义上分为: 容器(container) 算法(algorithm) 迭代器(iterator)
//容器和算法之间通过迭代器进行无缝连接。
//STL 几乎所有的代码都采用了模板类或者模板函数
/*STL六大组件*/
//STL大体分为六大组件,分别是:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器
//1. 容器:各种数据结构,如vector、list、deque、set、map等, 用来存放数据。
//2. 算法:各种常用的算法,如sort、?nd、copy、for_each等
//3. 迭代器:扮演了容器与算法之间的胶合剂。
//4. 仿函数:行为类似函数,可作为算法的某种策略。
//5. 适配器:一种用来修饰容器或者仿函数或迭代器接口的东西。
//6. 空间配置器:负责空间的配置与管理。
/*STL中容器、算法、迭代器*/
//容器:置物之所也
//STL容器就是将运用广泛的一些数据结构实现出来 常用的数据结构:数组, 链表, 树, 栈, 队列, 集合, 映射表 等
//这些容器分为序列式容器和关联式容器两种 :
//序列式容器:强调值的排序,序列式容器中的每个元素均有固定的位置。
//关联式容器 : 二叉树结构,各元素之间没有 严格的物理上的顺序关系
//算法:问题之解法也
//有限的步骤,解决逻辑或数学上的问题,这一门学科我们叫做算法(Algorithms)
//算法分为 : 质变算法和非质变算法。
//质变算法:是指运算过程中会更改区间内的元素的内容。例如拷贝,替换,删除等等
//非质变算法:是指运算过程中不会更改区间内的元素内容,例如查找、计数、遍历、寻找极值等等
//迭代器:容器和算法之间粘合剂
//提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该容器的内部表示方式。
//每个容器都有自己专属的迭代器
//迭代器使用非常类似于指针,初学阶段我们可以先理解迭代器为指针
//迭代器种类:
//输入迭代器 对数据的只读访问 只读,支持++、==、!=
//输出迭代器 对数据的只写访问 只写,支持++
//前向迭代器 读写操作,并能向前推进迭代器 读写,支持++、 == 、! =
//双向迭代器 读写操作,并能向前和向后操作 读写,支持++、--,
//随机访问迭代器 读写操作,可以以跳跃的方式访问任意数据,功能最强的迭代器 读写,支持++、--、[n]、 - n、<、 <= 、>、 >=
//常用的容器中迭代器种类为双向迭代器,和随机访问迭代器
/*容器算法迭代器初识*/
//STL中最常用的容器为Vector,可以理解为数组
/*vector存放内置数据类型*/
//需要包含头文件#incude<vector>
//容器:vector
//算法:for_each
//迭代器: vector<int>::iterator
void myPrint_vector(int val)
{
cout << val << endl;
}
void test23()
{
//创建一个vector容器,认为是一个数组
vector<int> v;
//向容器中插入数据,通过.push_back(数据)进行尾插
v.push_back(10);
v.push_back(20);
v.push_back(30);
v.push_back(40);
//通过迭代器访问容器中的数据
vector<int>::iterator itbegin = v.begin(); //.begin()是起始迭代器,指向容器中第一个元素,本质是指针
vector<int>::iterator itend = v.end(); //.end()是结束迭代器,指向容器中最后一个元素的下一个位置,本质是指针
//第一种遍历方式
while (itbegin != itend)
{
cout << *itbegin << endl;//解引用取出数据
itbegin++;
}
//第二种遍历方式
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << endl;
}
//第三种遍历方式
//利用STL提供的遍历算法,需要包含头文件#include<algorithm>
for_each(v.begin(), v.end(), myPrint_vector);//只写函数名就可以,不用加括号
}
/*vector存放自定义数据类型*/
class Person_v
{
public:
Person_v(string name, int age)
{
this->m_Age = age;
this->m_Name = name;
}
public:
int m_Age;
string m_Name;
};
void test24()
{
vector<Person_v> v;
Person_v p1("a", 1);
Person_v p2("b", 1);
Person_v p3("c", 1);
Person_v p4("d", 1);
Person_v p5("e", 1);
//向容器中添加数据
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
//遍历容器中的数据 通过(*it).对姓名和年龄进行取值,或者通过it->进行取值
//for里的<>里是啥数据类型,it就是指向什么数据类型的指针,这里it是一个Person_v的指针
//通过(*it).可以取出Person_v里的成员属性或者通过it->得到成员属性
for (vector<Person_v>::iterator it = v.begin(); it != v.end(); it++)
{
cout << "姓名:" << (*it).m_Name << "\t年龄:" << (*it).m_Age << endl;
cout << "姓名:" << it->m_Name << "\t年龄:" << it->m_Age << endl;
}
}
//存放自定义数据类型的指针
void test25()
{
vector<Person_v*> v;
Person_v p1("a", 1);
Person_v p2("b", 1);
Person_v p3("c", 1);
Person_v p4("d", 1);
Person_v p5("e", 1);
//向容器中添加数据
v.push_back(&p1);
v.push_back(&p2);
v.push_back(&p3);
v.push_back(&p4);
v.push_back(&p5);
//遍历容器
//for里面的<>是什么数据类型,it就是指向什么数据类型的指针,这里it是一个Person_v*的指针(指针的指针)
//通过(*it)可以得到Person_v的指针,再通过(*(*it)).或者(*it)->可以得到成员属性
for (vector<Person_v*>::iterator it = v.begin(); it != v.end(); it++)
{
cout << "---------------------------" << endl;
cout << "姓名:" << (*(*it)).m_Name << "\t年龄:" << (*(*it)).m_Age << endl;
cout << "姓名:" << (*it)->m_Name << "\t年龄:" << (*it)->m_Age << endl;
}
}
/*vector容器嵌套容器*/
void test26()
{
vector<vector<int>> v;
//创建小容器
vector<int>v1;
vector<int>v2;
vector<int>v3;
vector<int>v4;
//向小容器中添加数据
for (int i = 0; i < 4; i++)
{
v1.push_back(i + 1);
v2.push_back(i + 2);
v3.push_back(i + 3);
v4.push_back(i + 4);
}
//将小容器插入到大容器中
v.push_back(v1);
v.push_back(v2);
v.push_back(v3);
v.push_back(v4);
//通过大容器,把所有数据遍历一遍
for (vector<vector <int>>::iterator it = v.begin(); it != v.end(); it++)
{
//it是指向容器的指针,(*it)是容器
for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
{
cout << *vit << endl;
}
cout << endl;
}
}
/*string基本概念*/
//本质:
//string是C++风格的字符串,而string本质上是一个类
//string和char * 区别:
//char * 是一个指针 string是一个类,类内部封装了char*,管理这个字符串,是一个char*型的容器。
//特点:
//string 类内部封装了很多成员方法
//例如:查找find,拷贝copy,删除delete 替换replace,插入insert
//string管理char*所分配的内存,不用担心复制越界和取值越界等,由类内部进行负责
/*string构造函数*/
//构造函数原型:
//string(); //创建一个空的字符串 例如: string str;
//string(const char* s); //使用字符串s初始化
//string(const string& str); //使用一个string对象初始化另一个string对象
//string(int n, char c); //使用n个字符c初始化
void test27()
{
string s1;//默认构造
const char *str = "Hello world!";
string s2(str);//使用字符串初始化
cout << "s2=" << s2 << endl;
string s3(s2);//拷贝构造,使用一个string对象初始化另一个string
cout << "s3=" << s3 << endl;
string s4(10, 'a');//10个a
cout << "s4=" << s4 << endl;
}
/*string赋值操作*/
//功能描述:
//给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赋给当前字符串
void test28()
{
string str1;
str1 = "hello";
cout << "str1=" << str1 << endl;
string str2;
str2 = str1;
cout << "str2=" << str2 << endl;
string str3;
str3 = '3';
cout << "str3=" << str3 << endl;
string str4;
str4.assign("hello world!");
cout << "str4=" << str4 << endl;
string str5;
str5.assign("helloworld", 5);
cout << "str5=" << str5 << endl;
string str6;
str6.assign("Hello C++");
cout << "str6=" << str6 << endl;
string str7;
str7.assign(10, 'w');//10个w
cout << "str7=" << str7 << endl;
}
//总结:
//string的赋值方式很多, operator= 这种方式是比较实用的
/*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 pos, int n); //字符串s中从第pos个位置开始的n个字符连接到字符串结尾
void test29()
{
string str1 = "我";
str1 += "爱学习";
cout << "str1=" << str1 << endl;
str1 += ':';
cout << "str1=" << str1 << endl;
string str2 = "数学、C++";
str1 += str2;
cout << "str1=" << str1 << endl;
string str3 = "I";
str3.append(" love");
cout << "str3=" << str3 << endl;
str3.append(" game abcf", 5);
cout << "str3=" << str3 << endl;
str3.append(str2);
cout << "str3=" << str3 << endl;
string str4 = "helloworld";
str3.append(str4, 5, 5);
cout << "str3=" << str3 << endl;
}
/*string查找和替换*/
//功能描述:
//查找:查找指定字符串是否存在
//替换:在指定的位置替换字符串
//函数原型:
//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) const; //查找str后一次位置,从pos开始查找
//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 = 0) const; //查找字符c后一次出现位置
//string& replace(int pos, int n, const string& str); //替换从pos开始n个字符为字符串str
//string& replace(int pos, int n,const char* s);//替换从pos开始的n个字符为字符串s
void test30()
{
string str1 = "abcdefgde";
int pos = str1.find("df");
cout << "pos=" << pos << endl;
if (pos == -1)
{
cout << "未找到字符串" << endl;
}
else
{
cout << "找到字符串" << endl;
}
//rfind和find的区别
//rfind从右往左查找;find从左往右查找
pos = str1.rfind("de");
cout << "pos=" << pos << endl;
}
void test31()
{
string str1 = "abcdefg";
//从1号位置起,3个字符替换为“1111”
str1.replace(1, 3, "1111");
cout << "str1=" << str1 << endl;
}
//总结:
//find查找是从左往后,rfind从右往左
//find找到字符串后返回查找的第一个字符位置,找不到返回 - 1
//replace在替换时,要指定从哪个位置起,多少个字符,替换成什么样的字符串
/*string字符串比较*/
//功能描述:
//字符串之间的比较
//比较方式:
//字符串比较是按字符的ASCII码进行对比
//= 返回 0
//> 返回 1
//< 返回 - 1
//函数原型:
//int compare(const string &s) const;//与字符串s比较
//int compare(const char *s) const;//与字符串s比较
void test32()
{
string str1 = "hello";
string str2 = "xello";
if (str1.compare(str2)== 0)
{
cout << "str1=str2" << endl;
}
else if (str1.compare(str2) > 0)
{
cout << "str1>str2" << endl;
}
else
{
cout << "str1<str2" << endl;
}
}
//总结:字符串对比主要是用于比较两个字符串是否相等,判断谁大谁小的意义并不是很大
/*string字符存取*/
//string中单个字符存取方式有两种
//char& operator[](int n);//通过[]方式取字符
//char& at(int n);//通过at方法获取字符
void test33()
{
string str = "hello";
cout << "str=" << str << endl;
for (int i = 0; i < str.size(); i++)//string.size()用来输出字符串长度
{
cout << str[i] << " " ;
}
cout << endl;
for (int i = 0; i < str.size(); i++)
{
cout << str.at(i) << " ";
}
cout << endl;
//修改单个字符
str[0] = 'x';
cout << "str=" << str << endl;
str.at(1) = 'x';
cout << "str=" << str << endl;
}
//总结:string字符串中单个字符存取有两种方式,利用 [ ] 或 at
/*string插入和删除*/
//功能描述:
//对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个字符
void test34()
{
string str = "hello";
//插入
str.insert(1, "111");
cout << "str=" << str << endl;//h111ello
//删除
str.erase(1, 3);
cout << "str=" << str << endl;//hello
}
//总结:插入和删除的起始下标都是从0开始
/*string子串*/
//功能描述:
//从字符串中获取想要的子串
//函数原型:
//string substr(int pos = 0, int n = npos) const;//返回由pos开始的n个字符组成的字符串
void test35()
{
string str = "abcdef";
cout << "str=" << str << endl;
string subStr = str.substr(1, 3);
cout << "str=" << subStr << endl;
}
//实用操作
void test36()
{
string email = "hello@sina.com";
//从邮件地址中获取用户名信息
int pos = email.find("@");
string userName = email.substr(0, pos);
cout << "userName=" << userName << endl;
}
//总结:灵活的运用求子串功能,可以在实际开发中获取有效的信息
/*vector容器*/
/*vector基本概念*/
//功能:
//vector数据结构和数组非常相似,也称为单端数组
//vector与普通数组区别:
//不同之处在于数组是静态空间,而vector可以动态扩展
//静态空间容量是一定的,不能再扩展,比如原来有5个容量,那就只能装5个数
//动态扩展:
//并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝新空间,释放原空间
//vector容器的迭代器是支持随机访问的迭代器
/*vector构造函数*/
//功能描述:
//创建vector容器
//函数原型:
//vector<T> v;//采用模板实现类实现,默认构造函数
//vector(v.begin(), v.end());//将v[begin(), end())区间中的元素拷贝给本身。 注意是前闭后开区间
//vector(n, elem);//构造函数将n个elem拷贝给本身。
//vector(const vector &vec);//拷贝构造函数。
void printVector(vector<int> &v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test37()
{
vector<int>v1;//默认构造 无参构造
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
//通过区间方式进行构造
vector<int> v2(v1.begin(), v1.end());
printVector(v2);
//n个elem方式构造
vector<int>v3(10, 100);
printVector(v3);
//拷贝构造
vector<int>v4(v3);
printVector(v4);
}
//总结:vector的多种构造方式没有可比性,灵活使用即可
/*vector赋值操作*/
//功能描述:
//给vector容器进行赋值
//函数原型:
//vector& operator=(const vector &vec); //重载等号操作符
//assign(beg, end);//将[beg, end)区间中的数据拷贝赋值给本身。注意是前闭后开
//assign(n, elem);//将n个elem拷贝赋值给本身。
void test38()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
cout << "------------" << endl;
//等号赋值
vector<int>v2;
v2 = v1;
printVector(v2);
cout << "---------------" << endl;
//assign
vector<int>v3;
v3.assign(v1.begin(), v1.end());
printVector(v3);
cout << "---------------" << endl;
//n个elem方式
vector<int>v4;
v4.assign(10, 100);
printVector(v4);
cout << "---------------" << endl;
}
//总结: vector赋值方式比较简单,使用operator=,或者assign都可以
/*vector容量和大小*/
//功能描述:
//对vector容器的容量和大小操作
//函数原型:
//empty(); //判断容器是否为空
//capacity(); //容器的容量 容量capacity要≥size
//size(); //返回容器中元素的个数
//resize(int num); //重新指定容器的长度为num,若容器变长,则以默认值0填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除。
//resize(int num, elem); //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。
//如果容器变短,则末尾超出容器长度的元素被删除
void test39()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
if (v1.empty())//为真代表容器为空
{
cout << "v1为空" << endl;
}
else
{
cout << "v1不为空" << endl;
cout << "v1的容量为:" << v1.capacity() << endl;
cout << "v1的大小为:" << v1.size() << endl;
}
v1.resize(15);//如果重新指定比原来的长了,默认用0来填充
printVector(v1);
v1.resize(5);//比原来短了去掉后面的
printVector(v1);
v1.resize(16, 100);//也可以指定填充的数据
printVector(v1);
}
//总结:
//判断是否为空-- - empty
//返回元素个数-- - size
//返回容器容量-- - capacity
//重新指定大小-- - resize
/*vector插入和删除*/
//功能描述:
//对vector容器进行插入、删除操作
//函数原型:
//push_back(ele);//尾部插入元素ele
//pop_back(); //删除后一个元素
//insert(const_iterator pos, ele); //迭代器指向位置pos插入元素ele
//insert(const_iterator pos, int count,ele); //迭代器指向位置pos插入count个元素ele
//erase(const_iterator pos);//删除迭代器指向的元素
//erase(const_iterator start, const_iterator end); //删除迭代器从start到end之间的元素
//clear();//删除容器中所有元素
void test40()
{
vector<int>v1;
//尾插
v1.push_back(10);
v1.push_back(20);
v1.push_back(30);
v1.push_back(40);
v1.push_back(50);
//遍历
printVector(v1);
//尾删
v1.pop_back();
printVector(v1);
//插入 第一个参数是迭代器
v1.insert(v1.begin(), 100);
printVector(v1);
v1.insert(v1.begin(), 2, 1000);
printVector(v1);
//删除 参数也是迭代器
v1.erase(v1.begin());
printVector(v1);
//v1.erase(v1.begin(), v1.end());//全部删除相当于清空
//printVector(v1);
//清空
v1.clear();
printVector(v1);
}
//总结:
//尾插 --- push_back
//尾删 --- pop_back
//插入 --- insert(位置迭代器)
//删除 --- erase(位置迭代器)
//清空 --- clear
/*vector数据存取*/
//功能描述:
//对vector中的数据的存取操作
//函数原型:
//at(int idx);//返回索引idx所指的数据
//operator[];//返回索引idx所指的数据
//front();//返回容器中第一个数据元素
//back();//返回容器中后一个数据元素
void test41()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
for (int i = 0; i < v1.size(); i++)
{
//利用[]
cout << v1[i] << " ";
//利用at
cout << v1.at(i) << " ";
}
cout << endl;
//第一个元素
cout << v1.front() << endl;
//最后一个元素
cout << v1.back() << endl;
}
//总结:
//除了用迭代器获取vector容器中元素,[]和at也可以
//front返回容器第一个元素
//back返回容器后一个元素
/*vector互换容器*/
//功能描述:
//实现两个容器内元素进行互换
//函数原型:
//swap(vec); // 将vec与本身的元素互换
void test42()
{
vector<int>v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
vector<int>v2;
for (int i = 10; i > 0; i--)
{
v2.push_back(i);
}
printVector(v2);
cout << "------------" << endl;
v1.swap(v2);
printVector(v1);
printVector(v2);
}
//实际用途
//巧用swap可以收缩内存空间
void test43()
{
vector<int>v1;
for (int i = 0; i < 100000; i++)
{
v1.push_back(i);
}
cout << "v1的容量为:" << v1.capacity() << endl;
cout << "v1的大小为:" << v1.size() << endl;
v1.resize(3);
cout << "v1的容量为:" << v1.capacity() << endl;
cout << "v1的大小为:" << v1.size() << endl;
//巧用swap收缩内存
vector<int>(v1).swap(v1);
cout << "v1的容量为:" << v1.capacity() << endl;
cout << "v1的大小为:" << v1.size() << endl;
}
//总结:swap可以使两个容器互换,可以达到实用的收缩内存效果
//巧用swap收缩内存
//vector<int>(v1).swap(v1);
/*vector预留空间*/
//功能描述:
//减少vector在动态扩展容量时的扩展次数
//函数原型:
//reserve(int len); //容器预留len个元素长度,预留位置不初始化,元素不可访问
void test44()
{
vector<int>v1;
//利用reserve预留空间
v1.reserve(100000);
//统计开辟次数
int num = 0;
int *p = NULL;
for (int i = 0; i < 100000; i++)
{
v1.push_back(i);
if (p != &v1[0])//如果不等于首地址
{
p = &v1[0];//重新开辟内存的时候,首地址发生变化
num++;
}
}
cout << "num=" << num << endl;
}
//总结:如果数据量较大,可以一开始利用reserve预留空间
int main()
{
/*vector预留空间*/
test44();
/*vector互换容器*/
test42();
test43();
/*vector数据存取*/
test41();
/*vector插入和删除*/
test40();
/*vector容量和大小*/
test39();
/*vector赋值操作*/
test38();
/*vector构造函数*/
test37();
/*string子串*/
test35();
test36();
/*string插入和删除*/
test34();
/*string字符存取*/
test33();
/*string字符串比较*/
test32();
/*string查找和替换*/
test30();
test31();
/*string字符串拼接*/
test29();
/*string赋值操作*/
test28();
/*string构造函数*/
test27();
/*vector容器嵌套容器*/
test26();
/*vector存放自定义数据类型*/
test24();
test25();
/*vector存放内置数据类型*/
test23();
/*类模板案例*/
test21();
test22();
/*类模板与友元*/
test19();
test20();
/*类模板分文件编写*/
test18();
/*类模板成员函数类外实现*/
test17();
/*类模板与继承*/
test15();
test16();
/*类模板对象做函数参数*/
test12();
test13();
test14();
/*类模板中成员函数创建时机*/
test11();
/*类模板与函数模板区别*/
test09();
test10();
/*类模板语法*/
test08();
/*模板的局限性*/
test06();
test07();
/*普通函数与函数模板的调用规则*/
test05();//如果函数模板和普通函数都可以实现,优先调用普通函数
/*普通函数与函数模板的区别*/
test04();
/*函数模板注意事项*/
test03();
/*函数模板语法*/
test01();
system("pause");
return 0;
}