C++自学笔记3.0(STL模板)
更多教程笔记请查看我的上一篇文章:点击跳转
C++自学之旅3.0(STL模板)开始!
下面介绍的是algorithm这个C++内置的算法函数模板
algorithm:
for_each遍历算法
// algorithm算法模板-for_each
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
//普通函数
// for_each会不断的调用这个函数进行输出,这里用到了函数指针
void print01(int val)
{
cout << val << " ";
}
//仿函数
class Print02
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
//常用遍历算法 for_each
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
//遍历,前两个参数是要遍历的容器区间,第三个参数可以是函数也可以是仿函数的函数对象
for_each(v.begin(), v.end(), print01);
cout << endl;
//传入的是仿函数的匿名对象
for_each(v.begin(), v.end(), Print02());
}
int main()
{
test01();
return 0;
}
transform搬运算法
// algorithm算法模板-transform
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
class Transform
{
public:
//因为操作的是vector里int类型的数据,所以要返回int类型
int operator()(int v)
{
// return v;
//可以在搬运过程中加上逻辑运算让结果不一样
return v + 100;
}
};
class Myprint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
//目标容器
vector<int> vTarget;
//重新指定容量,目标容器必须大于原容器
vTarget.resize(v.size());
//利用transform将第一个容器搬运到第二个容器,最后一个参数是匿名对象
transform(v.begin(), v.end(), vTarget.begin(), Transform());
//输出
for_each(vTarget.begin(), vTarget.end(), Myprint());
cout << endl;
}
int main()
{
test01();
return 0;
}
find查找算法
// algorithm算法模板-find查找算法
#include <iostream>
using namespace std;
//使用find需要包含algorithm头文件
#include <algorithm>
#include <string>
#include <vector>
void printVector(vector<int> &v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
//查找内置的数据类型
void test01()
{
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
//查找容器中是否有5这个元素,前两个参数是容器区间,第三个参数是要查找的值
//返回的是一个容器的迭代器
vector<int>::iterator it = find(v.begin(), v.end(), 5);
//如果it指向容器的尾指针则表示没有找到这个元素
if (it == v.end())
{
//查找失败
cout << "find NULL!" << endl;
}
else
{
//查找成功
cout << "find success!" << *it << endl;
}
// printVector(v);
}
//查找自定义的数据类型
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
//重载operator==符号,让find知道如何查找Person的数据类型
// const是为了防止它修改底层代码
bool operator==(const Person &p)
{
//如果名字和年龄都相等那么就是要找的那个数
if (this->m_Name == p.m_Name && this->m_Age == p.m_Age)
{
return true;
}
else
{
return false;
}
}
string m_Name;
int m_Age;
};
void test02()
{
vector<Person> v;
//创建数据
Person p1("aaa", 10);
Person p2("bbb", 20);
Person p3("ccc", 30);
Person p4("ddd", 40);
//将数据放入到容器中
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
Person pp("bbb", 20);
//查找容器里面是否有p2这个对象
//知识点 自定义数据类型不能直接比较需要重载
// vector<Person>::iterator it = find(v.begin(), v.end(), p2);
//或者直接创建一个一样的其他对象进行比较
vector<Person>::iterator it = find(v.begin(), v.end(), pp);
if (it == v.end())
{
cout << "find NULL" << endl;
}
else
{
cout << "find success! name: " << it->m_Name << " age: " << it->m_Age << endl;
}
}
int main()
{
// test01();
test02();
return 0;
}
find_if查找算法
// algorithm算法模板-find_if查找算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
#include <string>
//仿函数
class GreaterFive
{
public:
bool operator()(int val)
{
return val > 5;
}
};
//查找内置的数据类型
void test01()
{
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
//查找容器里大于5的数,前两个参数是容器的区间,第三个参数是函数对象
//返回的是容器的迭代器
vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());
//如果it等于尾指针就是没有找到
if (it == v.end())
{
//没有找到
cout << "find NULL" << endl;
}
else
{
//找到了!
cout << "find success!" << endl;
for (; it != v.end(); it++)
{
cout << *it << " ";
}
}
}
//查找自定义的数据类型
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
class Greater20
{
public:
bool operator()(Person &p)
{
return p.m_Age > 20;
}
};
void test02()
{
vector<Person> v;
//创建数据
Person p1("aaa", 10);
Person p2("bbb", 20);
Person p3("ccc", 30);
Person p4("ddd", 40);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
//查找容器中年龄大于20的对象
vector<Person>::iterator it = find_if(v.begin(), v.end(), Greater20());
if (it == v.end())
{
cout << "find NULL!" << endl;
}
else
{
cout << "find success!" << endl;
for (; it != v.end(); it++)
{
cout << "name: " << it->m_Name << " age: " << it->m_Age << endl;
}
}
}
int main()
{
// test01();
test02();
return 0;
}
adjacent_find查找算法
// algorithm算法模板-adjacent_find查找算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
#include <string>
void test01()
{
// adjacent_find作用是查找相邻的重复元素
vector<int> v;
v.push_back(0);
v.push_back(2);
v.push_back(0);
v.push_back(3);
v.push_back(1);
v.push_back(4);
v.push_back(3);
v.push_back(3);
//查找相邻的重复元素,返回的是一个容器的迭代器
vector<int>::iterator it = adjacent_find(v.begin(), v.end());
//如果it等于尾指针则表示查找失败
if (it == v.end())
{
cout << "find NULL!" << endl;
}
else
{
//查找成功
cout << "find success!" << endl;
for (; it != v.end(); it++)
{ // 3 3
cout << *it << endl;
}
}
}
int main()
{
test01();
return 0;
}
binary_search二分查找算法
// algorithm算法模板-binary_search二分查找算法
#include <iostream>
#include <algorithm>
#include <vector>
using namespace std;
//常用的查找算法 binary_search
void test01()
{
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
//查找容器中是否有9这个元素,前两个参数是容器的区间,第三个参数是要查找的值
//返回的是一个bool类型
//注意容器这里必须是有序且升序排序的序列,不可以是降序的
//降序的话可以使用重载版本,在后面添加greater<int>()这个仿函数
bool ret = binary_search(v.begin(), v.end(), 9);
//如果找到了就为真,未找到为假
if (ret)
{
cout << "find success!" << endl;
}
else
{
cout << "find NULL!" << endl;
}
}
int main()
{
test01();
return 0;
}
count统计查找算法
// algorithm算法模板-count统计查找算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
//统计内置数据类型
void test01()
{
vector<int> v;
for (int i = 0; i < 10; i++)
{
for (int j = 10; j >= i; j--)
{
v.push_back(j);
}
}
//利用count统计出容器中4的元素个数
//返回值是一个整型
int num = count(v.begin(), v.end(), 4);
cout << "4 num: " << num << endl;
}
//统计自定义的数据类型
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
//统计自定义的数据类型时需要仿函数operator重载==号,返回类型是bool
//注意:为了防止修改底层代码需要加const
bool operator==(const Person &p)
{
if (this->m_Age == p.m_Age)
{
return true;
}
else
{
return false;
}
}
string m_Name;
int m_Age;
};
void test02()
{
vector<Person> v;
Person p1("aaa", 35);
Person p2("bbb", 35);
Person p3("ccc", 35);
Person p4("ddd", 30);
Person p5("eee", 40);
Person p("vvv", 35);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
//统计与p年龄相同的人有多少个
//注意:统计自定义的数据类型时需要仿函数operator重载==号
int num = count(v.begin(), v.end(), p);
cout << "and vvv age num: " << num << endl;
}
int main()
{
// test01();
test02();
return 0;
}
count_if统计查找算法
// algorithm算法模板-count_if统计查找算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
//统计内置的数据类型
class Greater20
{
public:
//仿函数
bool operator()(int val)
{
return val > 20;
}
};
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(40);
v.push_back(30);
v.push_back(20);
v.push_back(40);
v.push_back(20);
//查找容器里有多少个大于20的数,前两个参数是容器的区间,第三个参数是仿函数的函数对象
//返回值是一个int类型
int num = count_if(v.begin(), v.end(), Greater20());
cout << ">20 num: " << num << endl;
}
//统计自定义的数据类型
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
//创建谓词供count_if使用
class AgeGreater20
{
public:
bool operator()(const Person &p)
{
return p.m_Age > 20;
}
};
void test02()
{
vector<Person> v;
Person p1("aaa", 35);
Person p2("bbb", 35);
Person p3("ccc", 35);
Person p4("ddd", 40);
Person p5("eee", 20);
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
//统计 年龄大于20的人员个数 传入的是一个仿函数的匿名函数对象
int num = count_if(v.begin(), v.end(), AgeGreater20());
cout << ">20 age num: " << num << endl;
}
int main()
{
// test01();
test02();
return 0;
}
sort排序算法
// algorithm算法模板-sort排序算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
#include <functional>
void myPrint(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(30);
v.push_back(50);
v.push_back(20);
v.push_back(40);
//利用sort进行升序
sort(v.begin(), v.end());
//打印
for_each(v.begin(), v.end(), myPrint);
cout << endl;
//利用sort仿函数进行降序
sort(v.begin(), v.end(), greater<int>());
//打印
for_each(v.begin(), v.end(), myPrint);
cout << endl;
}
int main()
{
test01();
return 0;
}
random_shuffle洗牌算法
// algorithm算法模板-random_shuffle洗牌算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
#include <ctime>
void myPrint(int val)
{
cout << val << " ";
}
void test01()
{
//加上随机数种子,这样洗牌就不会每次都相同
srand((unsigned int)time(NULL));
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
//利用洗牌算法打乱容器中数据的顺序
random_shuffle(v.begin(), v.end());
//输出
for_each(v.begin(), v.end(), myPrint);
cout << endl;
}
int main()
{
test01();
return 0;
}
merge合并排序算法
// algorithm算法模板-merge合并排序算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
void myPrint(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v1;
vector<int> v2;
//注意:使用merge时合并的两个容器必须是有序序列
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i + 1);
}
//目标容器,将上面两个容器放入目标容器中
vector<int> vTarget;
//要将目标容器的大小扩大到上面两个容器合并的大小
vTarget.resize(v1.size() + v2.size());
//前四个参数是两个容器的区间,第五个参数是目标容器的头部
//当两个容器合并后会自动按升序排序
//如果要合并后降序排序需要在第六个参数加greater<int>()
merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
//输出
for_each(vTarget.begin(), vTarget.end(), myPrint);
cout << endl;
}
int main()
{
test01();
return 0;
}
reverse反转算法
// algorithm算法模板-reverse反转算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
void myPrint(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(30);
v.push_back(50);
v.push_back(20);
v.push_back(40);
//反转前
cout << "open: " << endl;
for_each(v.begin(), v.end(), myPrint);
cout << endl;
//反转,传递的是容器的区间
reverse(v.begin(), v.end());
//反转后
cout << "end: " << endl;
for_each(v.begin(), v.end(), myPrint);
}
int main()
{
test01();
return 0;
}
copy拷贝算法
// algorithm算法模板-copy拷贝算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
void myPrint(int val)
{
cout << val << " ";
}
void test01()
{
vector<int> v1;
v1.push_back(10);
v1.push_back(30);
v1.push_back(50);
v1.push_back(20);
v1.push_back(40);
vector<int> v2;
//在拷贝前目标容器要开辟空间
v2.resize(v1.size());
//拷贝前
cout << "open: " << endl;
for_each(v2.begin(), v2.end(), myPrint);
cout << endl;
//拷贝,前两个参数传递的是容器的区间,第三个参数是目标容器的头部
copy(v1.begin(), v1.end(), v2.begin());
//拷贝后
cout << "end: " << endl;
for_each(v2.begin(), v2.end(), myPrint);
}
int main()
{
test01();
return 0;
}
replace替换算法
// algorithm算法模板-replace替换算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(30);
v.push_back(50);
v.push_back(20);
v.push_back(40);
v.push_back(10);
v.push_back(20);
//替换前
cout << "open: " << endl;
for_each(v.begin(), v.end(), myPrint());
cout << endl;
//替换,前两个参数传递的是容器的区间,第三个参数是要被替换的数值,第四个参数是要替换的数值
//将容器的区间内部所有的20替换为2000
replace(v.begin(), v.end(), 20, 2000);
//替换后
cout << "end: " << endl;
for_each(v.begin(), v.end(), myPrint());
}
int main()
{
test01();
return 0;
}
replace_if指定替换算法
// algorithm算法模板-replace_if指定替换算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
//写一个谓词当作判断条件
class Greater30
{
public:
bool operator()(int val)
{
return val >= 30;
}
};
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(30);
v.push_back(50);
v.push_back(20);
v.push_back(40);
v.push_back(10);
v.push_back(20);
//替换前
cout << "open: " << endl;
for_each(v.begin(), v.end(), myPrint());
cout << endl;
//替换,前两个参数传递的是容器的区间,第三个参数是要被替换的仿函数规则(谓词),第四个参数是要替换的数值
//将容器的区间内部所有大于等于30的数 替换为3000
replace_if(v.begin(), v.end(), Greater30(), 3000);
//替换后
cout << "end: " << endl;
for_each(v.begin(), v.end(), myPrint());
}
int main()
{
test01();
return 0;
}
swap交换算法
// algorithm算法模板-swap交换算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
vector<int> v1;
vector<int> v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
v2.push_back(i + 100);
}
//交换前
cout << "open: " << endl;
cout << "v1: " << endl;
for_each(v1.begin(), v1.end(), myPrint());
cout << endl;
cout << "v2: " << endl;
for_each(v2.begin(), v2.end(), myPrint());
cout << endl;
//交换,注意:在交换时两个容器的类型必须相同
swap(v1, v2);
//交换后
cout << "--------------------------------------" << endl;
cout << "end: " << endl;
cout << "v1: " << endl;
for_each(v1.begin(), v1.end(), myPrint());
cout << endl;
cout << "v2: " << endl;
for_each(v2.begin(), v2.end(), myPrint());
cout << endl;
}
int main()
{
test01();
return 0;
}
set_intersection交集算法
// algorithm算法模板-set_intersection交集算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
//所谓交集就是两个容器中相同的部分
//注意:两个容器必须是有序的
vector<int> v1;
vector<int> v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i); // 0~9
v2.push_back(i + 5); // 5~14
}
//将两个容器的交集部分存入到第三个容器中
vector<int> vTarget;
//需要提前指定大小
//最坏的情况 大容器包含小容器 开辟空间 取小容器的size即可
vTarget.resize(min(v1.size(), v2.size()));
//获取交集,前四个参数是两个容器的区间,第五个参数是目标容器的头部
//返回值是一个迭代器,itEnd指向的是重复的最后位置,但是容器没完,后面还有初始化的0
vector<int>::iterator itEnd = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
//输出 用itend 就不会出现剩余的空间补0,其实不是不补0而是没有遍历到后面的0
for_each(vTarget.begin(), itEnd, myPrint());
cout << endl;
}
int main()
{
test01();
return 0;
}
set_union并集算法
// algorithm算法模板-set_union并集算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
//所谓并集就是两个容器中不相同的部分,如果有相同的部分会优先去掉另一个相同的部分
//只保留一个原来的相同的部分
//注意:两个容器必须是有序的
vector<int> v1;
vector<int> v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i); // 0~9
v2.push_back(i + 5); // 5~14
}
//将两个容器的并集部分存入到第三个容器中
vector<int> vTarget;
//需要提前指定大小
//最坏的情况 两个容器没有交集 并集就是两个容器相加
vTarget.resize(v1.size() + v2.size());
//获取并集,前四个参数是两个容器的区间,第五个参数是目标容器的头部
//返回值是一个容器的迭代器,指向目标容器的并集的最后部分
vector<int>::iterator it = set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
//输出 用it 就不会出现剩余的空间补0,其实不是不补0而是没有遍历到后面的0
for_each(vTarget.begin(), it, myPrint());
cout << endl;
}
int main()
{
test01();
return 0;
}
set_difference差集算法
// algorithm算法模板-set_difference差集算法
#include <iostream>
using namespace std;
#include <algorithm>
#include <vector>
class myPrint
{
public:
void operator()(int val)
{
cout << val << " ";
}
};
void test01()
{
//所谓差集就是两个容器中不相同(不属于交集)的部分
//按照顺序如果是v1和v2的差集那就只保留v1中和v2不同的部分
//如果是v2和v1的差集那就只保留v2中和v1不同的部分,也就是:
// v1和v2的差集:0 1 2 3 4
// v2和v1的差集: 10 11 12 13 14
//它们各自都把相同的部分去掉了,只保留自身
vector<int> v1;
vector<int> v2;
for (int i = 0; i < 10; i++)
{
v1.push_back(i); // 0~9
v2.push_back(i + 5); // 5~14
}
//将两个容器的差集部分存入到第三个容器中
vector<int> vTarget;
//需要提前指定大小
//最坏的情况 两个容器没有交集 要取两个容器中大的size作为目标容器开辟的空间
vTarget.resize(max(v1.size(), v2.size()));
// v1和v2的差集为:
cout << "v1 n v2: " << endl;
//获取差集,前四个参数是两个容器的区间,第五个参数是目标容器的头部
//返回值是一个容器的迭代器,指向目标容器的差集的结束位置
vector<int>::iterator it = set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin());
//输出 用it 就不会出现剩余的空间补0,其实不是不补0而是没有遍历到后面的0
for_each(vTarget.begin(), it, myPrint());
cout << endl;
// v2和v1的差集为:
cout << "v2 n v1: " << endl;
//获取差集,前四个参数是两个容器的区间,第五个参数是目标容器的头部
//返回值是一个容器的迭代器,指向目标容器的差集的结束位置
it = set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), vTarget.begin());
//输出 用it 就不会出现剩余的空间补0,其实不是不补0而是没有遍历到后面的0
for_each(vTarget.begin(), it, myPrint());
cout << endl;
}
int main()
{
test01();
return 0;
}
下面介绍的是vector这个C++内置的动态数组容器
vector:
vector的用法
// vector的用法
#include <iostream>
using namespace std;
//用vector的容器需要包含这个头文件
#include <vector>
//用其他的STL模板算法需要包含这个头文件
#include <algorithm>
void myPrint(int val)
{
cout << val << " ";
}
void test01()
{
//<>括号里面是要操作的数据类型
vector<int> arr;
//从尾部插入数据
arr.push_back(10);
arr.push_back(20);
arr.push_back(30);
arr.push_back(40);
//通过迭代器访问容器中的数据,arr.begin()指向容器中的第一个元素
vector<int>::iterator itBegin = arr.begin();
// arr.end()指向容器中的最后一个元素的下一个位置
vector<int>::iterator itEnd = arr.end();
//第一种遍历方式:
// while (itBegin != itEnd)
// {
// cout << *itBegin << " ";
// itBegin++;
// }
//第二种遍历方式
// for (vector<int>::iterator it = arr.begin(); it != arr.end(); it++)
// {
// cout << *it << " ";
// }
//第三种遍历方式,用algorithm里面提供的模板
//第一个参数是数组的起始位置,第二个参数是数组的结束位置,第三个参数是自定义的函数名
//在遍历的时候它会不停的调用这个函数,向这个函数传参数,再在函数里面进行输出
for_each(arr.begin(), arr.end(), myPrint);
}
int main()
{
test01();
return 0;
}
vector操作自定义的数据类型
// vector操作自定义的数据类型
#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include <string>
//自定义一个Person的数据类型
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
void test01()
{
Person p1("aaa", 10);
Person p2("bbb", 20);
Person p3("ccc", 30);
Person p4("ddd", 40);
Person p5("eee", 50);
vector<Person> v;
//通过尾插的方式插入自定义的数据类型
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
v.push_back(p5);
//遍历容器中的数据
for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
{
//迭代器指向的是一个对象,所以可以用对象的方式获得属性
// cout << "name: " << (*it).m_Name << " age: " << (*it).m_Age << endl;
//因为it本身就是一个指针,所以可以通过指针的方式直接访问对象里的属性
cout << "name: " << it->m_Name << " age: " << it->m_Age << endl;
}
}
void test02()
{
Person p1("aaa", 10);
Person p2("bbb", 20);
Person p3("ccc", 30);
Person p4("ddd", 40);
Person p5("eee", 50);
//第二种方式:存放自定义数据类型的指针
vector<Person *> v;
//通过尾插的方式插入自定义的数据类型的地址
v.push_back(&p1);
v.push_back(&p2);
v.push_back(&p3);
v.push_back(&p4);
v.push_back(&p5);
//遍历容器
for (vector<Person *>::iterator it = v.begin(); it != v.end(); it++)
{
//因为it是一个指针类型的迭代器,而指针类型的迭代器通过*解引用的方式解出来的是一个存放着对象地址的指针,所以还要通过指针的方式去访问对象里面的属性
cout << "name: " << (*it)->m_Name << " age: " << (*it)->m_Age << endl;
}
}
int main()
{
// test01();
test02();
return 0;
}
vector嵌套vector
// vector嵌套vector
#include <iostream>
using namespace std;
#include <vector>
#include <algorithm>
#include <string>
void test01()
{
//其实也是相当于一个数组里面存放着多个其他数组,可以看作是二维数组
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)----vector<int> 当it解引用后出来的是小容器,所以还要遍历一遍小容器
for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++)
{
// vit---vector<int> v1[0] 此时vie就等于小容器里面的首地址,通过解引用的方式拿到数组里面的值
//当一层循环遍历完了后也就是把大容器中的第一个数组遍历完了,然后就会遍历下一个数组
cout << *vit << " ";
}
cout << endl;
}
}
int main()
{
test01();
return 0;
}
vector实战
// vector实战
#include <iostream>
using namespace std;
#include <vector>
//输出
void printVector(vector<int> &v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
//默认构造 无参构造
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
//通过区间的方式进行构造,也就是把v1中从第1号位置到倒数第1号位置之间的全部数据复制到v2中
vector<int> v2(v1.begin(), v1.end());
printVector(v2);
//通过elem方式构造,也就是把10个100赋值给v3
vector<int> v3(10, 100);
printVector(v3);
//拷贝构造,将v3中的内容拷贝到v4中
vector<int> v4(v3);
printVector(v4);
}
int main()
{
test01();
return 0;
}
vector函数重载
#include <iostream>
using namespace std;
#include <vector>
void printVector(vector<int> &v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
//赋值 operator=
vector<int> v2;
//其底层是函数重载,将v1的内容赋值给v2
v2 = v1;
printVector(v2);
// assign
vector<int> v3;
//通过成员函数assign,将v1区间里的内容复制到v3中
v3.assign(v1.begin(), v1.end());
printVector(v3);
// n个elem方式赋值
vector<int> v4;
//将10个100赋值到v4中
v4.assign(10, 100);
printVector(v4);
}
int main()
{
test01();
return 0;
}
vector指定大小
#include <iostream>
using namespace std;
#include <vector>
void printVector(vector<int> &v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
printVector(v1);
//为真,代表容器为空
if (v1.empty())
{
cout << "v1 NULL" << endl;
}
else
{
//容器不为空
cout << "v1 not NULL" << endl;
//输出数组的容量,容量机制是快要插满时就扩展至原来的1.5倍
cout << "v1 area: " << v1.capacity() << endl;
//输出数组的长度
cout << "v1 size:" << v1.size() << endl;
}
//重新指定大小,会默认用0来填充数组剩余的位置
// v1.resize(15);
//也可以用100或者其他数替换0的位置作为填充值
v1.resize(15, 100);
printVector(v1);
//如果重新指定的比原来短了,超出部分会删除掉
v1.resize(5);
printVector(v1);
}
int main()
{
test01();
return 0;
}
vector插入和删除
#include <iostream>
using namespace std;
#include <string>
#include <vector>
void printVector(vector<int> &v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
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);
//插入,在头部最前面插入一个100
v1.insert(v1.begin(), 100);
printVector(v1);
//利用重载的版本,在头部最前面插入2个1000
v1.insert(v1.begin(), 2, 1000);
printVector(v1);
//删除,删除最前面头部的元素
v1.erase(v1.begin());
printVector(v1);
//利用重载的版本,将数组从开始到结束区间的所有数据全部删除
// v1.erase(v1.begin(), v1.end());
//清空,效果和上面一样
// v1.clear();
//删除倒数第二个位置上的元素
v1.erase(v1.end() - 2);
//删除中间位置的元素
v1.erase(v1.begin() + v1.size() / 2);
printVector(v1);
}
int main()
{
test01();
return 0;
}
vector用at的方式访问元素
// vector实战
#include <iostream>
using namespace std;
#include <vector>
void test01()
{
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] << " ";
}
cout << endl;
//利用at方式访问元素
for (int i = 0; i < v1.size(); i++)
{
cout << v1.at(i) << " ";
}
cout << endl;
//利用front成员函数,获取第一个元素
cout << "one: " << v1.front() << endl;
//利用back成员函数,获取最后一个元素
cout << "end: " << v1.back() << endl;
}
int main()
{
test01();
return 0;
}
vector巧用swap收缩内存
// vector实战
#include <iostream>
using namespace std;
#include <vector>
void printVector(vector<int> &v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
vector<int> v1;
for (int i = 0; i < 10; i++)
{
v1.push_back(i);
}
//交换前
cout << "open:" << endl;
printVector(v1);
vector<int> v2;
for (int i = 10; i > 0; i--)
{
v2.push_back(i);
}
printVector(v2);
//交换后
cout << "end:" << endl;
//通过swap成员函数,把v1和v2的元素交换
v1.swap(v2);
printVector(v1);
printVector(v2);
}
// swap的调用时机
void test02()
{
vector<int> v;
for (int i = 0; i < 100000; i++)
{
v.push_back(i);
}
//输出容量
cout << "v area: " << v.capacity() << endl;
//输出长度
cout << "v size: " << v.size() << endl;
//重新指定大小
v.resize(3);
//输出容量,重新指定大小后,容量并不会缩小,浪费空间
cout << "v area: " << v.capacity() << endl;
//输出长度
cout << "v size: " << v.size() << endl;
//巧用swap收缩内存
//利用拷贝构造创建一个匿名对象,让匿名对象和原本的数组进行交换
//在用完后匿名对象就自动释放了,然后原本的数组的容量就变成了匿名对象的容量
vector<int>(v).swap(v);
//输出容量
cout << "v area: " << v.capacity() << endl;
//输出长度
cout << "v size: " << v.size() << endl;
}
int main()
{
// test01();
test02();
return 0;
}
vector利用reverse预留空间
// vector实战
#include <iostream>
using namespace std;
#include <vector>
void printVector(vector<int> &v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
vector<int> v;
//利用reserve预留空间
v.reserve(100000);
//当利用reserve为动态数组预留了空间以后,编译器就不会自动开辟内存了,减少了内存的占用
//统计开辟的次数
int num = 0;
int *p = NULL;
for (int i = 0; i < 100000; i++)
{
v.push_back(i);
//因为内存不连续,所以就会挪地方。用头部指针来确定位置
if (p != &v[0])
{
//每次扩容释放原来的空间并重新申请空间,指针指向的地址就会和v[0]不同
p = &v[0];
//所以在它重新开辟的时候判断指针就可以得到它开辟的次数
num++;
}
// Vector的扩容策略是找一块更大的空间复制原来的东西过去,所以首地址会变
}
//如果没有利用reserve预留空间,那么编译器要new18次内存,但是预留了之后只需要new一次
cout << "num = " << num << endl;
//总结:如果一开始数据量比较大可以用reserve预留空间来减少编译器new的次数
}
int main()
{
test01();
return 0;
}
下面介绍的是string这个C++内置的字符串容器
string:
string的本质
// string本质是一个类,底层是一个char*在维护
#include <iostream>
using namespace std;
//用string必须包含这个头文件
#include <string>
#include <algorithm>
void test01()
{
//默认构造
string s1;
//可以用一个c语言风格的字符串来初始化string
const char *str = "hello,world";
//有参构造
string s2(str);
cout << "s2 = " << s2 << endl;
//拷贝构造
string s3(s2);
cout << "s3 = " << s3 << endl;
//成员函数,其本质是复制10个字符a到数组中
string s4(10, 'a');
cout << "s4 = " << s4 << endl;
}
int main()
{
test01();
return 0;
}
string的赋值操作
// string的赋值操作
#include <iostream>
using namespace std;
#include <algorithm>
#include <string>
void test01()
{
string str1;
//正常赋值
str1 = "hello,world";
cout << "str1 = " << str1 << endl;
string str2;
//拷贝构造,其底层利用的函数重载=号
str2 = str1;
cout << "str2 = " << str2 << endl;
string str3;
str3 = 'a';
cout << "str3 = " << str3 << endl;
string str4;
//利用内置的模板函数赋值
str4.assign("hello C++");
cout << "str4 = " << str4 << endl;
string str5;
//将字符串的前5个字符拿过来保存到str5中
str5.assign("hello C++", 5);
cout << "str5 = " << str5 << endl;
string str6;
//利用拷贝构造函数赋值
str6.assign(str5);
cout << "str6 = " << str6 << endl;
string str7;
//复制10个v字符到str7中
str7.assign(10, 'v');
cout << "str7 = " << str7 << endl;
}
int main()
{
test01();
return 0;
}
string 字符串拼接
// string 字符串拼接
#include <iostream>
using namespace std;
#include <algorithm>
#include <string>
void test01()
{
string str1 = "i";
//通过+=号实现字符串拼接
str1 += " love you";
cout << "str1 = " << str1 << endl;
//追加字符
str1 += ':';
cout << "str1 = " << str1 << endl;
string str2 = "LOL DNF";
str1 += str2;
cout << "str1 = " << str1 << endl;
string str3 = "T";
//通过成员函数拼接字符串
str3.append(" Love ");
cout << "str3 = " << str3 << endl;
str3.append("game abcde", 4);
//将字符串中的前4个字符拼接到str3原本的字符串的后面
cout << "str3 = " << str3 << endl;
//将str2字符串中的内容追加到str3后面
// str3.append(str2);
//将str2中从0号位置开始到3号位置结束的0~2下标的3个字符串截取到str3中
// str3.append(str2, 0, 3);
//将str2中的从第4号位置开始(0~3)往后的3个字符截取到str3字符串中,参数1是从哪个位置开始截取,参数2是截取字符的个数
str3.append(str2, 4, 3);
cout << "str3 = " << str3 << endl;
}
int main()
{
test01();
return 0;
}
string的查找和替换
// string的查找和替换
#include <iostream>
using namespace std;
#include <string>
// 1.查找
void test01()
{
string str1 = "abcdefgde";
//查找str1字符串中有没有de这个字符串,从0号位置开始查找,返回值是一个下标
int pos = str1.find("de");
//如果没有这个字符串存在就返回-1
if (pos == -1)
{
cout << "find error!" << endl;
}
else
{
// 3 返回的是字符第一次出现的位置
cout << "pos = " << pos << endl;
}
// rfind和find的区别是:find是从左往右查,rfind是从右往左查
pos = str1.rfind("de");
cout << "pos = " << pos << endl;
}
// 2.替换
void test02()
{
string str1 = "abcdefg";
// replace替换函数,把从1号位置起,往后3个字符(bcd)替换成1111
str1.replace(1, 3, "1111");
// a1111efg
cout << "str1 = " << str1 << endl;
}
int main()
{
// test01();
test02();
return 0;
}
string字符串比较
// string字符串比较
#include <iostream>
using namespace std;
#include <string>
void test01()
{
//字符串比较是按ASCII进行比较的,一个一个字符的比
string str1 = "hello";
string str2 = "xello";
//调用成员函数进行比较,如果是相等则返回0
if (str1.compare(str2) == 0)
{
cout << "str1==str2" << endl;
}
else if (str1.compare(str2) > 0) //这里的意思是说把str1的所有字符按ASCII值逐个跟str2进行比较,如果出现str1当中的某个ASCII值大于str2的情况则返回1
{
cout << "str1>str2" << endl;
}
else
{
cout << "str1<str2" << endl;
}
}
int main()
{
test01();
return 0;
}
string的字符存取
// string 字符存取
#include <iostream>
using namespace std;
#include <string>
void test01()
{
string str = "hello";
// cout << "str = " << str << endl;
// 1.通过[]访问单个字符,其底层是函数重载,size()获取字符串的长度
for (int i = 0; i < str.size(); i++)
{
cout << str[i] << " ";
}
cout << endl;
// 2.通过成员函数at的方式访问单个字符
for (int i = 0; i < str.size(); i++)
{
cout << str.at(i) << " ";
}
cout << endl;
//修改单个字符,[]的方式
str[0] = 'x';
// xello
cout << "str = " << str << endl;
//修改单个字符,at的方式:
str.at(1) = 'x';
// xxllo
cout << "str = " << str << endl;
}
int main()
{
test01();
return 0;
}
string的插入和删除
// string的插入和删除
#include <iostream>
using namespace std;
#include <string>
void test01()
{
string str = "hello";
//插入,在第1号位置(e)的前面插入111
str.insert(1, "111");
// h111ello
cout << "str = " << str << endl;
//删除,把从第1号位置(1)起,往后3个字符(111)删除
str.erase(1, 3);
// hello
cout << "str = " << str << endl;
}
int main()
{
test01();
return 0;
}
string子串(字符串截取)
// string子串(字符串截取)
#include <iostream>
using namespace std;
#include <string>
void test01()
{
string str = "abcdef";
//把从第1号位置开始起,往后3个字符(bcd)截取到substr中
string substr = str.substr(1, 3);
cout << "substr = " << substr << endl;
}
//实用操作
void test02()
{
string email = "zhangsan@email.com";
//从邮件的地址中获取用户名的信息,也就是获取@字符前面的字符串
//先找到@字符的下标
int pos = email.find("@");
//从0开始起,截取pos(8)个字符到userName中
//因为从0号位置起是包含0的,所以截取8个实际上截取的是0~7
string userName = email.substr(0, pos);
cout << "userName = " << userName << endl;
}
int main()
{
// test01();
test02();
return 0;
}
下面介绍的是stack这个C++内置的栈容器
stack:
stack容器的用法
// stack容器
#include <iostream>
using namespace std;
//使用栈容器需要包含的头文件
#include <stack>
void test01()
{
//创建一个栈
stack<int> s;
//栈是一种先进后出,后进先出的容器
//入栈
s.push(10);
s.push(20);
s.push(30);
s.push(40);
//查看栈的长度
cout << "s size:" << s.size() << endl;
//判断栈是否为空,为空返回真,不为空返回假,通过取反的操作循环遍历出栈,直到栈为空为止
while (!s.empty())
{
//查看栈顶元素 40 30 20 10 因为是先进后出,40是最后进的栈,所以先输出40
cout << "top: " << s.top() << endl;
//出栈
s.pop();
}
//查看栈的长度
cout << "s size:" << s.size() << endl;
}
int main()
{
test01();
return 0;
}
下面介绍的是queue这个C++内置的队列容器
queue:
queue容器的基本用法
// queue容器
#include <iostream>
using namespace std;
//使用队列容器需要包含的头文件
#include <queue>
#include <string>
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
void test01()
{
//队列是一个先进先出的容器
//创建一个队列
queue<Person> q;
//队列也可以存储自定义的数据类型
Person p1("tanshen", 30);
Person p2("swk", 100);
Person p3("zbj", 900);
Person p4("sashen", 800);
//入队
q.push(p1);
q.push(p2);
q.push(p3);
q.push(p4);
//查看队列的大小
cout << "q size: " << q.size() << endl;
//判断队列是否为空,为空返回真,通过取反的操作一直循环出队,直到队列为空为止
while (!q.empty())
{
//查看队头
cout << "top--name: " << q.front().m_Name << " age: " << q.front().m_Age << endl;
//查看队尾
cout << "back--name: " << q.back().m_Name << " age: " << q.back().m_Age << endl;
//出队
q.pop();
}
//查看队列的大小
cout << "q size: " << q.size() << endl;
}
int main()
{
test01();
return 0;
}
下面介绍的是set这个C++内置的集合容器
set:
set容器的构造和赋值
// set容器的构造和赋值
#include <iostream>
using namespace std;
//使用set集合容器必须要加这个头文件
#include <set>
void printSet(const set<int> &s)
{
for (set<int>::const_iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
// set容器不允许插入重复的数据,且容器内部是有序的,其底层是一个二叉树
set<int> s1;
//插入数据,注意:set没有尾插和头插,只有insert插入方式
s1.insert(100);
s1.insert(20);
s1.insert(300);
s1.insert(40);
s1.insert(500);
//这里最后的20不会显示,因为set不允许插入重复值
s1.insert(20);
//无论插入的是否有序,set内部都会自动排序
printSet(s1);
//拷贝构造 将s1的数据全部拷贝到s2中
set<int> s2(s1);
printSet(s2);
// operator=赋值
set<int> s3;
s3 = s2;
printSet(s3);
}
int main()
{
test01();
return 0;
}
set大小和交换
// set大小和交换
#include <iostream>
using namespace std;
#include <set>
void printSet(const set<int> &s)
{
for (set<int>::const_iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
//大小
void test01()
{
set<int> s1;
//插入数据
s1.insert(10);
s1.insert(20);
s1.insert(30);
s1.insert(40);
//打印容器
printSet(s1);
//判断set是否为空,为空返回真
if (s1.empty())
{
cout << "s1 NULL" << endl;
}
else
{
cout << "s1 not NULL" << endl;
//查看set的元素个数
cout << "s1 size: " << s1.size() << endl;
}
}
//交换
void test02()
{
set<int> s1;
//插入数据
s1.insert(10);
s1.insert(20);
s1.insert(30);
s1.insert(40);
set<int> s2;
//插入数据
s2.insert(100);
s2.insert(200);
s2.insert(300);
s2.insert(400);
//交换前
cout << "open: " << endl;
printSet(s1);
printSet(s2);
//交换
s1.swap(s2);
//交换后
cout << "end: " << endl;
printSet(s1);
printSet(s2);
}
int main()
{
// test01();
test02();
return 0;
}
set插入和删除
// set插入和删除
#include <iostream>
using namespace std;
#include <set>
void printSet(const set<int> &s)
{
for (set<int>::const_iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
set<int> s1;
//插入
s1.insert(30);
s1.insert(30);
s1.insert(20);
s1.insert(40);
//输出
printSet(s1);
//删除 set中的第一个元素 因为set内部会自动排序,所以删除的其实是20,不是第一个插入的30
s1.erase(s1.begin());
printSet(s1);
//删除的重载版本,直接传入数据就可以自动删除容器中对应的数据
s1.erase(40);
printSet(s1);
//清空区间的值
s1.erase(s1.begin(), s1.end());
printSet(s1);
//清空,跟上面一样的效果
s1.clear();
printSet(s1);
}
int main()
{
test01();
return 0;
}
set的查找和统计
// set的查找和统计
#include <iostream>
using namespace std;
#include <set>
void test01()
{
set<int> s1;
//插入数据
s1.insert(10);
s1.insert(20);
s1.insert(30);
s1.insert(40);
//查找 返回的是一个迭代器
set<int>::iterator pos = s1.find(40);
//如果返回的不是容器当中的尾指针则表示找到了
if (pos != s1.end())
{
cout << "find success!" << *pos << endl;
}
else
{
cout << "find error!" << endl;
}
}
//统计
void test02()
{
set<int> s1;
//插入数据
s1.insert(10);
s1.insert(20);
s1.insert(30);
s1.insert(30);
s1.insert(30);
s1.insert(30);
s1.insert(40);
s1.insert(30);
//统计30的个数
int num = s1.count(300);
// 1 不过插入多少相同的数在set里面都只有1个
cout << "num: " << num << endl;
}
int main()
{
// test01();
test02();
return 0;
}
set与multiset的区别
// set与multiset的区别
#include <iostream>
using namespace std;
#include <set>
void test01()
{
set<int> s;
// set的底层是一个pair的数据类型,而pair是一个成对出现的数据类型
//下面定义一个pair的数据类型,第一个数据类型是迭代器,第二个数据类型是bool
//可以用这个数据类型定义一个变量用来接收set插入返回的结果
pair<set<int>::iterator, bool> ret = s.insert(10);
// ret是一个set+bool的数据类型,如果为真则表示set插入成功
if (ret.second)
{
//插入成功
cout << "insert success!" << endl;
}
else
{
//插入失败
cout << "insert error!" << endl;
}
ret = s.insert(10);
//在第二次向set容器插入相同的数据时插入失败了
if (ret.second)
{
//插入成功
cout << "insert2 success!" << endl;
}
else
{
//插入失败
cout << "insert2 error!" << endl;
}
//这是multiset,允许往容器中插入相同的数据
multiset<int> ms;
//允许插入重复值,其它的成员函数和set相同
ms.insert(10);
ms.insert(10);
ms.insert(10);
ms.insert(10);
for (multiset<int>::iterator it = ms.begin(); it != ms.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
int main()
{
test01();
return 0;
}
set容器排序
// set容器排序
#include <iostream>
#include <set>
using namespace std;
class MyCompare
{
public:
//利用函数重载进行排序,第一个()代表重载()符号,第二个()代表函数的参数列表
//仿函数的返回值是一个bool类型
bool operator()(int v1, int v2)
{
return v1 > v2;
}
};
void printSet(const set<int> &s)
{
for (set<int>::const_iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
//因为原本的模板列表变了,所以不能再用上面的,要重写输出函数
void printSet2(const set<int, MyCompare> &s)
{
for (set<int, MyCompare>::const_iterator it = s.begin(); it != s.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
// set容器本身是有序的,但是可以通过仿函数修改它的排序规则
set<int> s1;
for (int i = 10; i < 15; i++)
{
for (int j = 15; j >= i; j--)
{
s1.insert(j);
}
}
//排序前
cout << "open: " << endl;
printSet(s1);
//默认是升序排序,指定排序规则为降序排序
set<int, MyCompare> s2;
for (int i = 10; i < 15; i++)
{
for (int j = 15; j >= i; j--)
{
s2.insert(j);
}
}
//排序后:
cout << "end: " << endl;
printSet2(s2);
}
int main()
{
test01();
return 0;
}
set容器排序2—自定义数据类型排序
// set容器排序2--自定义数据类型排序
#include <iostream>
using namespace std;
#include <set>
#include <string>
class Person
{
public:
Person(string name, int age)
{
this->m_Name = name;
this->m_Age = age;
}
string m_Name;
int m_Age;
};
//利用仿函数指定排序规则
class comparePerson
{
public:
//在对比过程中不可修改,所以要加上const
bool operator()(const Person &p1, const Person &p2)
{
//按照年龄 降序
return p1.m_Age > p2.m_Age;
}
};
//输出
void printSet(const set<Person, comparePerson> &s)
{
for (set<Person, comparePerson>::const_iterator it = s.begin(); it != s.end(); it++)
{
cout << "name: " << it->m_Name << " age: " << it->m_Age << endl;
}
}
void test01()
{
//利用仿函数修改排序规则
set<Person, comparePerson> s;
//创建Perosn对象
Person p1("liubei", 24);
Person p2("zs", 28);
Person p3("lisi", 25);
Person p4("wangwu", 21);
//插入数据
s.insert(p1);
s.insert(p2);
s.insert(p3);
s.insert(p4);
//遍历数据
printSet(s);
}
int main()
{
test01();
return 0;
}
下面介绍的是pair这个C++内置的对组容器,一般都和map哈希表容器配合使用
pair:
pair容器的基本用法
// pair对组容器
#include <iostream>
using namespace std;
#include <string>
void test01()
{
//使用pair不需要引入其他头文件
//创建pair,<>括号里面是两个不同的数据类型,()括号里面是给这两个不同的类型赋初值,也可以理解为有参构造函数
pair<string, int> p("Tom", 20);
//输出pair里面的值,第一个值是first,第二个值是second
cout << "name: " << p.first << " age: " << p.second << endl;
//第二种方式: 在make_pair里面赋值
pair<string, int> p2 = make_pair("Jerry", 30);
//访问第一个数据是first,访问第二个数据是second
cout << "name: " << p2.first << " age: " << p2.second << endl;
}
int main()
{
test01();
return 0;
}
下面介绍的是map这个C++内置哈希表容器
map:
map容器构造和赋值
// map容器构造和赋值
#include <iostream>
using namespace std;
//要使用哈希容器需要引入这个头文件
#include <map>
void printMap(const map<int, int> &m)
{
for (map<int, int>::const_iterator it = m.begin(); it != m.end(); it++)
{
//在map输出时要输出一个对组,可以用(*it).的方式,也可以用->指针的方式,first是对组左边的值,second是对组右边的值
cout << "key: " << (*it).first << " value: " << it->second << endl;
}
cout << endl;
}
void test01()
{
// map底层是用二叉树实现的
//创建一个map,<>符号里面的值是成对出现的,第一个是key值,起到索引作用,第二个是value值,起到实值的作用
map<int, int> m;
//插入数据,因为map里面的值是成对出现的,所以要使用pair成对的插入值
//可以理解为一个map里面存放着多个pair,其中左边的1起到的是索引key的作用,右边的10起到的是value实值的作用
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(3, 30));
m.insert(pair<int, int>(2, 20));
m.insert(pair<int, int>(4, 40));
//输出 注意:无论插入的顺序是什么,最后还是会按照key的顺序排序
printMap(m);
//拷贝构造
map<int, int> m2(m);
printMap(m);
//赋值
map<int, int> m3;
m3 = m2;
printMap(m3);
}
int main()
{
test01();
return 0;
}
map容器大小和交换
// map容器大小和交换
#include <iostream>
using namespace std;
#include <map>
void printMap(const map<int, int> &m)
{
for (map<int, int>::const_iterator it = m.begin(); it != m.end(); it++)
{
cout << "key: " << it->first << " value: " << it->second << endl;
}
cout << endl;
}
//大小
void test01()
{
map<int, int> m;
//通过pair往map里插入数据
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(2, 20));
m.insert(pair<int, int>(3, 30));
//判断map是否为空,如果为空则返回真
if (m.empty())
{
//为空
cout << "map NULL!" << endl;
}
else
{
//不为空
cout << "map not NULL!" << endl;
//查看map的长度
cout << "m size: " << m.size() << endl;
}
}
//交换
void test02()
{
map<int, int> m;
//通过pair往map里插入数据
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(2, 20));
m.insert(pair<int, int>(3, 30));
map<int, int> m2;
//通过pair往map里插入数据
m2.insert(pair<int, int>(4, 100));
m2.insert(pair<int, int>(5, 200));
m2.insert(pair<int, int>(6, 300));
//交换前
cout << "open: " << endl;
printMap(m);
printMap(m2);
//交换
m.swap(m2);
//交换后
cout << "end: " << endl;
printMap(m);
printMap(m2);
}
int main()
{
// test01();
test02();
return 0;
}
map的插入和删除
// map的插入和删除
#include <iostream>
using namespace std;
#include <map>
void printMap(const map<int, int> &m)
{
for (map<int, int>::const_iterator it = m.begin(); it != m.end(); it++)
{
cout << "key: " << it->first << " value: " << it->second << endl;
}
cout << endl;
}
void test01()
{
map<int, int> m;
//第一种插入方式:
m.insert(pair<int, int>(1, 10));
//第二种插入方式: make_pair也可以创建出一个对组
m.insert(make_pair(2, 20));
//第三种 通过迭代器插入
m.insert(map<int, int>::value_type(3, 30));
//第四种: 通过重载运算符[]的方式插入,[]里面的值代表key,=右边的值代表value
m[4] = 40;
//也可以利用[] 访问到value,但是要注意key下标越界的问题,如果越界了那么value会默认为0
cout << m[4] << endl;
//输出
printMap(m);
//删除 将map中第一个元素删除
m.erase(m.begin());
printMap(m);
//通过key的方式删除,将map中key为3的数据删除,注意:不能按照value删除
m.erase(3);
printMap(m);
//按照区间的方式清空
m.erase(m.begin(), m.end());
//清空,跟上面一样
m.clear();
}
int main()
{
test01();
return 0;
}
map的查找和统计
// map的查找和统计
#include <iostream>
using namespace std;
#include <map>
void test01()
{
map<int, int> m;
m.insert(pair<int, int>(1, 10));
m.insert(pair<int, int>(2, 20));
m.insert(pair<int, int>(3, 30));
//通过key查找,返回一个迭代器
map<int, int>::iterator pos = m.find(3);
//如果迭代器不等于尾指针则表示找到了
if (pos != m.end())
{
//输出找到的key和value值
cout << "find success! key = " << (*pos).first << " value = " << (*pos).second << endl;
}
else
{
cout << "find error!" << endl;
}
//统计,通过key找到对应的值的个数
m.insert(pair<int, int>(3, 30));
m.insert(pair<int, int>(3, 40));
m.insert(pair<int, int>(3, 50));
//注意:map不允许插入重复的key的元素,无论插入多少,只要key是相同的那么就只会保留第一个插入的数据
// multimap的统计个数可能会大于1
int num = m.count(3);
//所以统计map的key的个数num永远是1
cout << "num = " << num << endl;
cout << m[3] << endl;
}
int main()
{
test01();
return 0;
}
map容器排序
// map容器排序
#include <iostream>
using namespace std;
#include <map>
class MyCompare
{
public:
//仿函数
bool operator()(int v1, int v2)
{
//降序
return v1 > v2;
}
};
void printMap(const map<int, int, MyCompare> &m)
{
for (map<int, int, MyCompare>::const_iterator it = m.begin(); it != m.end(); it++)
{
cout << "key: " << it->first << " value: " << it->second << endl;
}
cout << endl;
}
void test01()
{
// map默认的排序规则是按key值从小到大升序排序,要改变排序规则需要借助仿函数
map<int, int, MyCompare> m;
m.insert(make_pair(1, 10));
m.insert(make_pair(2, 20));
m.insert(make_pair(3, 30));
m.insert(make_pair(4, 40));
m.insert(make_pair(5, 50));
printMap(m);
}
int main()
{
test01();
return 0;
}
map容器排序-自定义数据类型排序
// map容器排序-自定义数据类型排序
#include <iostream>
using namespace std;
#include <map>
#include <string>
class Person
{
public:
Person(string name, int age)
{
this->m_Age = age;
this->m_Name = name;
}
string m_Name;
int m_Age;
};
class MyCompare
{
public:
bool operator()(int v1, int v2)
{
return v1 > v2;
}
};
void printMap(const map<int, Person, MyCompare> &m)
{
for (map<int, Person, MyCompare>::const_iterator it = m.begin(); it != m.end(); it++)
{
cout << "key-age: " << it->first << " value-name: "
<< it->second.m_Name << " age: " << it->second.m_Age << endl;
}
cout << endl;
}
void test01()
{
//利用仿函数修改排序规则
map<int, Person, MyCompare> m;
Person p1("zs", 18);
Person p2("lisi", 20);
Person p3("wangwu", 28);
Person p4("zaoliu", 19);
//将对象里的年龄作为key
m.insert(make_pair(p1.m_Age, p1));
m.insert(make_pair(p2.m_Age, p2));
m.insert(make_pair(p3.m_Age, p3));
m.insert(make_pair(p4.m_Age, p4));
printMap(m);
}
int main()
{
test01();
return 0;
}
下面介绍的是list这个C++内置双向链表容器
list:
list容器的基本使用
// list容器
#include <iostream>
using namespace std;
//使用链表需要包含的头文件
#include <list>
//输出
void printList(const list<int> &L)
{
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
//链表可以对任意位置插入和删除元素
//缺点:遍历元素没有数组快,占用的空间比数组大
//创建一个链表
list<int> L1;
// STL中的链表是一个双向链表,也就是每个节点有两个指针,一个指向前,一个指向后
//利用尾插添加数据
L1.push_back(10);
L1.push_back(20);
L1.push_back(30);
L1.push_back(40);
//遍历
printList(L1);
//利用区间的方式构造,将L1区间中所有的数据复制到L2中
list<int> L2(L1.begin(), L1.end());
printList(L2);
//拷贝构造
list<int> L3(L2);
printList(L3);
// n个elem,将10个1000复制到L4中
list<int> L4(10, 1000);
printList(L4);
}
int main()
{
test01();
return 0;
}
list赋值和交换
// list赋值和交换
#include <iostream>
using namespace std;
#include <list>
void printList(const list<int> &L)
{
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
list<int> L1;
//利用尾插添加数据进链表
L1.push_back(10);
L1.push_back(20);
L1.push_back(30);
L1.push_back(40);
printList(L1);
//利用operator=赋值
list<int> L2;
L2 = L1;
printList(L2);
//利用区间赋值
list<int> L3;
L3.assign(L2.begin(), L2.end());
printList(L3);
list<int> L4;
// n个elem方式,也就是10个100赋值给L4
L4.assign(10, 100);
printList(L4);
}
//交换
void test02()
{
list<int> L1;
//利用尾插添加数据进链表
L1.push_back(10);
L1.push_back(20);
L1.push_back(30);
L1.push_back(40);
list<int> L2;
//将10个100赋值给L2
L2.assign(10, 100);
//交换前:
cout << "open: " << endl;
printList(L1);
printList(L2);
//交换,将L1和L2中的元素进行交换
L1.swap(L2);
//交换后
cout << "end: " << endl;
printList(L1);
printList(L2);
}
int main()
{
// test01();
test02();
return 0;
}
list大小操作
// list大小操作
#include <iostream>
using namespace std;
#include <list>
//输出
void printList(const list<int> &L)
{
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
list<int> L1;
//利用尾插添加数据进链表
L1.push_back(10);
L1.push_back(20);
L1.push_back(30);
L1.push_back(40);
//输出
printList(L1);
//判断list容器是否为空,如果为空返回真
if (L1.empty())
{
cout << "L1 NULL" << endl;
}
else
{
cout << "L1 not NULL" << endl;
//输出list容器的长度(个数)
cout << "L1 size:" << L1.size() << endl;
}
//重新指定大小,默认用0填充剩余空间
// L1.resize(10);
//重新指定大小,用1来填充剩余空间
L1.resize(10, 1);
printList(L1);
//重新指定大小,如果超出则将超出的部分删除
L1.resize(2);
printList(L1);
}
int main()
{
test01();
return 0;
}
list插入和删除
// list插入和删除
#include <iostream>
using namespace std;
#include <list>
void printList(const list<int> &L)
{
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
list<int> L;
//尾插
L.push_back(10);
L.push_back(20);
L.push_back(30);
//头插
L.push_front(100);
L.push_front(200);
L.push_front(300);
//输出 300 200 100 10 20 30 因为100~300是头插的,10~30是尾插的,所以300在最前面
printList(L);
//尾删 300 200 100 10 20 将最后一个元素30给删除了
L.pop_back();
printList(L);
//头删 200 100 10 20 将第一个元素300给删除了
L.pop_front();
printList(L);
//指定位置插入,在头部第一个元素的前面插入1000
L.insert(L.begin(), 1000);
// 1000 200 100 10 20
printList(L);
//通过迭代器插入
list<int>::iterator it = L.begin();
//在第二个元素(200)的前面插入2000
L.insert(++it, 2000);
// 1000 2000 200 100 10 20
printList(L);
//删除
it = L.begin();
//将头部第一个元素(1000)删除
L.erase(it);
// 2000 200 100 10 20
printList(L);
//通过迭代器将第二个元素(200)删除
it = L.begin();
L.erase(++it);
printList(L);
//移除
//尾插10000
L.push_back(10000);
L.push_back(10000);
L.push_back(10000);
L.push_back(10000);
printList(L);
//利用成员函数remove直接把10000删除,括号里面写要删除的数据,所有匹配的值都会被删除
L.remove(10000);
printList(L);
//清空
L.clear();
printList(L);
}
int main()
{
test01();
return 0;
}
list数据存取
// list数据存取
#include <iostream>
using namespace std;
#include <list>
void printList(const list<int> &L)
{
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
list<int> L1;
L1.push_back(10);
L1.push_back(20);
L1.push_back(30);
L1.push_back(40);
// L1[0] 不可以用中括号的方式访问list中的元素
// L1.at(0) 不可以用at的方式访问list中的元素
//原因:链表的数据不是连续存储的,不能用访问数组的方式访问链表
printList(L1);
//访问第一个元素
cout << "top: " << L1.front() << endl;
//访问最后一个元素
cout << "back: " << L1.back() << endl;
//迭代器不支持随机访问
list<int>::iterator it = L1.begin();
//错误,不允许直接+数,只能++或者--
// it = it + 1;
it++;
it--;
}
int main()
{
test01();
return 0;
}
list反转和排序
// list反转和排序
#include <iostream>
using namespace std;
#include <list>
void printList(const list<int> &L)
{
for (list<int>::const_iterator it = L.begin(); it != L.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
//反转
void test01()
{
list<int> L1;
for (int i = 1; i < 5; i++)
{
for (int j = 5; j >= i; j--)
{
L1.push_back(j);
}
}
//反转前
cout << "open: " << endl;
printList(L1);
//反转
L1.reverse();
//反转后
cout << "end: " << endl;
printList(L1);
}
//函数重载,使list的排序降序排序
bool myCompare(int v1, int v2)
{
return v1 > v2;
}
//排序
void test02()
{
list<int> L1;
for (int i = 1; i < 5; i++)
{
for (int j = 5; j >= i; j--)
{
L1.push_back(j);
}
}
//排序前:
cout << "open: " << endl;
printList(L1);
//默认升序排序,注意:不能用algorithm里面的sort排序模板,因为list不支持随机访问迭代器
//可以用内置的成员函数sort进行排序
L1.sort();
//排序后
cout << "end: " << endl;
printList(L1);
//利用函数重载降序排序
L1.sort(myCompare);
//降序排序后:
printList(L1);
}
int main()
{
// test01();
test02();
return 0;
}
list排序案例-自定义数据类型排序
// list排序案例-自定义数据类型排序
#include <iostream>
using namespace std;
#include <list>
#include <string>
class Person
{
public:
Person(string name, int age, int height)
{
this->m_Name = name;
this->m_Age = age;
this->m_Height = height;
}
//姓名
string m_Name;
//年龄
int m_Age;
//身高
int m_Height;
};
//指定排序规则
//如果要排序自定义类型则必须指定排序规则
bool comparePerson(Person &p1, Person &p2)
{
//高级排序:
if (p1.m_Age == p2.m_Age)
{
//如果年龄相同的情况下,按照身高降序排序
return p1.m_Height > p2.m_Height;
}
else
{
//按照年龄 升序排序:
return p1.m_Age < p2.m_Age;
}
}
void printList(list<Person> &L)
{
for (list<Person>::const_iterator it = L.begin(); it != L.end(); it++)
{
cout << "name: " << (*it).m_Name << " age: " << (*it).m_Age << " height: " << (*it).m_Height << endl;
}
}
void test01()
{
list<Person> L1;
Person p("swk", 20, 181);
Person p1("zbj", 29, 190);
Person p2("tanshen", 19, 175);
Person p3("shashen", 18, 165);
Person p4("zs", 18, 200);
Person p5("lisi", 29, 195);
//向容器中插入数据
L1.push_back(p);
L1.push_back(p1);
L1.push_back(p2);
L1.push_back(p3);
L1.push_back(p4);
L1.push_back(p5);
//输出排序前:
cout << "open: " << endl;
printList(L1);
cout << "------------------------------" << endl;
//排序,括号里面的是通过函数重载指定排序规则:
L1.sort(comparePerson);
//排序后:
cout << "end: " << endl;
printList(L1);
}
int main()
{
test01();
return 0;
}
下面介绍的是deque这个C++内置双端队列容器
deque:
deque容器的基本使用
// deque构造函数
#include <iostream>
using namespace std;
//使用deque容器必须包含这个头文件
#include <deque>
//输出,加了const后就变成了只读的一个迭代器
void printDeque(const deque<int> &d)
{
//通过迭代器输出
for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
{
//错误,加了const后容器中的数据就只读不可修改了
//*it = 100;
cout << *it << " ";
}
cout << endl;
}
void test01()
{
deque<int> d1;
//通过尾插法插入数据
for (int i = 0; i < 10; i++)
{
d1.push_back(i);
}
printDeque(d1);
//通过两个成员函数把d1所有区间的数据都赋值给d2
deque<int> d2(d1.begin(), d1.end());
printDeque(d2);
//将10个100赋值给d3
deque<int> d3(10, 100);
printDeque(d3);
//拷贝构造,把d3赋值给d4
deque<int> d4(d3);
printDeque(d4);
}
int main()
{
test01();
return 0;
}
deque赋值操作
// deque赋值操作
#include <iostream>
using namespace std;
#include <deque>
void printDeque(const deque<int> &d)
{
for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
deque<int> d1;
for (int i = 0; i < 10; i++)
{
d1.push_back(i);
}
//打印
printDeque(d1);
// operator=号赋值
deque<int> d2;
d2 = d1;
printDeque(d2);
// assign赋值
deque<int> d3;
d3.assign(d1.begin(), d1.end());
printDeque(d3);
deque<int> d4;
//赋值10个100
d4.assign(10, 100);
printDeque(d4);
}
int main()
{
test01();
return 0;
}
deque判断元素大小和长度
// deque判断元素大小和长度
#include <iostream>
using namespace std;
#include <deque>
void printDeque(const deque<int> &d)
{
for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
// deque其底层有一个中控器来控制里面的容器,无论增加多少个元素进去只要中控器能管理到就可以一直增加
deque<int> d1;
for (int i = 0; i < 10; i++)
{
d1.push_back(i);
}
//打印
printDeque(d1);
//判断是否为空,空返回真
if (d1.empty())
{
cout << "d1 NULL" << endl;
}
else
{
cout << "d1 not NULL" << endl;
//获取容器的长度
cout << "d1 size: " << d1.size() << endl;
//注意:deque没有返回容量的成员函数
}
//重新指定大小,用0来填充多余的空间
d1.resize(15);
printDeque(d1);
//重新指定大小,指定用1来填充多余的空间
d1.resize(15, 1);
//重新指定大小,超出的部分会被删除
d1.resize(5);
}
int main()
{
test01();
return 0;
}
deque的插入和删除
// deque的插入和删除
#include <iostream>
using namespace std;
#include <deque>
void printDeque(const deque<int> &d)
{
for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
deque<int> d1;
//尾插
d1.push_back(10);
d1.push_back(20);
d1.push_back(30);
d1.push_back(40);
//头插
d1.push_front(100);
d1.push_front(200);
//打印 200 100 10 20 30 40 因为10~40是从尾部插入的,而200和100是从头部插入的,所以顺序不同
printDeque(d1);
//尾删
d1.pop_back();
printDeque(d1);
//头删
d1.pop_front();
printDeque(d1);
}
void test02()
{
deque<int> d1;
d1.push_back(10);
d1.push_back(20);
d1.push_front(100);
d1.push_front(200);
// 200 100 10 20
printDeque(d1);
//在头部第一个元素的前面插入1000
d1.insert(d1.begin(), 1000);
//在头部第一个元素的前面插入2个10000
d1.insert(d1.begin(), 2, 10000);
// 10000 10000 1000 200 100 10 20
printDeque(d1);
//按照区间进行插入
deque<int> d2;
d2.push_back(1);
d2.push_back(2);
d2.push_back(3);
//在d1的头部第一个元素的前面插入d2的全部数据
d1.insert(d1.begin(), d2.begin(), d2.end());
printDeque(d1);
}
void test03()
{
deque<int> d1;
d1.push_back(10);
d1.push_back(20);
d1.push_front(100);
d1.push_front(200);
//删除
deque<int>::iterator it = d1.begin();
//迭代器一开始指向容器中第一个元素,it++后迭代器指向第二个元素
it++;
//利用迭代器将第二个元素删除
d1.erase(it);
// 200 10 20
printDeque(d1);
//按照区间的方式删除,其实也就是清空
d1.erase(d1.begin(), d1.end());
printDeque(d1);
//利用成员函数清空
d1.clear();
}
int main()
{
// test01();
// test02();
test03();
return 0;
}
deque的数据存取
// deque的数据存取
#include <iostream>
using namespace std;
#include <deque>
void test01()
{
deque<int> d;
d.push_back(10);
d.push_back(20);
d.push_back(30);
d.push_front(100);
d.push_front(200);
d.push_front(300);
//通过[]方式访问元素
for (int i = 0; i < d.size(); i++)
{
// 300 200 100 10 20 30
cout << d[i] << " ";
}
cout << endl;
//通过at方式访问元素
for (int i = 0; i < d.size(); i++)
{
cout << d.at(i) << " ";
}
cout << endl;
//访问第一个元素
cout << "one: " << d.front() << endl;
//访问最后一个元素
cout << "end: " << d.back() << endl;
}
int main()
{
test01();
return 0;
}
deque排序
// deque排序
#include <iostream>
using namespace std;
//标准算法头文件
#include <algorithm>
#include <deque>
void printDeque(const deque<int> &d)
{
for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
bool cmp(int a, int b)
{
return a > b;
}
void test01()
{
deque<int> d;
d.push_back(10);
d.push_back(20);
d.push_back(30);
d.push_front(100);
d.push_front(200);
d.push_front(300);
//升序排序
sort(d.begin(), d.end());
printDeque(d);
//降序排序
sort(d.begin(), d.end(), cmp);
printDeque(d);
}
int main()
{
test01();
return 0;
}
下面介绍的是operator()这个C++内置仿函数重载的用法,以及谓词的概念。
operator():
仿函数重载()
//仿函数重载()
#include <iostream>
using namespace std;
#include <string>
class MyAdd
{
public:
int operator()(int v1, int v2)
{
return v1 + v2;
}
};
void test01()
{
//当一个类里有operator()重载函数,那么创建出来的对象就称为函数对象
//函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值
MyAdd myAdd;
cout << myAdd(10, 10) << endl;
}
//函数对象超出普通函数的概念,可以有自己的状态
class MyPrint
{
public:
MyPrint()
{
this->count = 0;
}
void operator()(string test)
{
cout << test << endl;
//统计使用次数
this->count++;
}
//记录内部的状态
int count;
};
void test02()
{
MyPrint myPrint;
myPrint("hello world");
myPrint("hello world");
myPrint("hello world");
myPrint("hello world");
cout << "myPrint count: " << myPrint.count << endl;
}
//函数对象可以作为参数传递
void doPrint(MyPrint &mp, string test)
{
//函数传了一个自定义类型数据,在传一个字符串,然后自定义数据在内部执行重载
mp(test);
}
void test03()
{
MyPrint myPrint;
doPrint(myPrint, "Hello c++");
}
int main()
{
// test01();
// test02();
test03();
return 0;
}
一元谓词
//一元谓词
#include <iostream>
using namespace std;
#include <string>
#include <vector>
#include <algorithm>
class GreaterFive
{
public:
//一元谓词:只有一个参数,返回类型是bool
bool operator()(int val)
{
return val > 5;
}
};
void test01()
{
//仿函数,返回值类型是bool类型,称为谓词
//在operator()仿函数重载时小括号里一个参数就是一元,两个参数就是二元
vector<int> v;
for (int i = 0; i < 10; i++)
{
v.push_back(i);
}
//查找容器中大于5的数字
// find_if是algorithm里面的模板算法,参数是传容器的区间,第三个参数传的是仿函数的函数对象
//可以用匿名的函数对象GreaterFive()替代,返回的是一个迭代器,传入什么容器就用什么容器的迭代器接收
vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive());
//如果迭代器指向容器的尾指针则表示未找到
if (it == v.end())
{
cout << "find error!" << endl;
}
else
{
//查找成功
cout << "find success!" << endl;
for (; it != v.end(); it++)
{
cout << *it << " ";
}
}
}
int main()
{
test01();
return 0;
}
二元谓词
//二元谓词
#include <iostream>
using namespace std;
#include <string>
#include <vector>
#include <algorithm>
class MyCompare
{
public:
//在对象里面重载()符号,是bool类型并有两个参数就是二元谓词
bool operator()(int v1, int v2)
{
return v1 > v2;
}
};
void PrintVector(vector<int> &v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
vector<int> v;
v.push_back(10);
v.push_back(40);
v.push_back(20);
v.push_back(30);
v.push_back(50);
sort(v.begin(), v.end());
//升序排序后:
cout << "open: " << endl;
PrintVector(v);
//使用函数对象 修改算法规则 变为从大到小降序排序
//这里的MyCompare就是正常的函数调用,只不过是匿名对象,在sort里面会调用这个函数,
//这时用到就是函数重载运算符
sort(v.begin(), v.end(), MyCompare());
cout << "--------------------------------------" << endl;
//降序排序后:
cout << "end: " << endl;
PrintVector(v);
}
int main()
{
test01();
return 0;
}
内建函数对象,算术仿函数
//内建函数对象,算术仿函数
#include <iostream>
using namespace std;
//使用内建函数对象需要包含这个头文件
#include <functional>
// negate 一元仿函数,取反仿函数
// plus 二元仿函数,加法
void test01()
{
//容器,内建仿函数都是类模板
//通过内置的函数创建一个函数对象
negate<int> n;
//对50进行取反: -50
cout << n(50) << endl;
}
void test02()
{
plus<int> p;
//两个整型相加: 30
cout << p(10, 20) << endl;
/*
类似的内置仿函数还有很多:
minus<T> 减法
multiplies<T> 乘法
divides<T> 除法
modulus<T> 取模
*/
}
int main()
{
// test01();
test02();
return 0;
}
内建函数对象,关系仿函数
//内建函数对象,关系仿函数
#include <iostream>
using namespace std;
#include <functional>
#include <vector>
#include <algorithm>
class MyCompare
{
public:
bool operator()(int v1, int v2)
{
return v1 > v2;
}
};
void printVector(vector<int> &v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << endl;
}
void test01()
{
//大于 greater<T>
vector<int> v;
v.push_back(10);
v.push_back(30);
v.push_back(20);
v.push_back(50);
v.push_back(40);
printVector(v);
//利用自定义函数对象实现降序排序
// sort(v.begin(), v.end(), MyCompare());
//利用内置函数对象实现降序排序
sort(v.begin(), v.end(), greater<int>());
printVector(v);
/*
类似的关系仿函数还有很多:
equal_to<T> 等于
not_equal_to<T> 不等于
greater<T> 大于
greater_equal<T> 大于等于
less<T> 小于
less_equal<T> 小于等于
*/
}
int main()
{
test01();
return 0;
}
内建仿函数-逻辑仿函数
//内建仿函数-逻辑仿函数
#include <iostream>
using namespace std;
#include <functional>
#include <vector>
#include <algorithm>
void printVector(vector<bool> &v)
{
for (vector<bool>::iterator it = v.begin(); it != v.end(); it++)
{
//可以在输出前面加上boolalpha让输出0/1变为输出false/true
cout << boolalpha << *it << " ";
}
cout << endl;
}
void test01()
{
//逻辑非 logical_not 也就是取反!
vector<bool> v;
// 在vector容器里:true为1,false为0
v.push_back(true);
v.push_back(false);
v.push_back(true);
v.push_back(false);
printVector(v);
//利用逻辑非 将容器v搬运到容器v2中,并执行取反操作
vector<bool> v2;
//将v2的大小变为v1的大小
v2.resize(v.size());
// transform包含在algorithm算法模板中
//其作用是将第一个容器的内容搬运到第二个容器中,其中第一个参数和第二个参数是第一个容器的区间
//第三个参数是要搬运到的容器的开始区间,第四个参数是逻辑仿函数用来取反,用来之后就
//可以将第一个容器中搬运到第二个容器的数据全部取反
transform(v.begin(), v.end(), v2.begin(), logical_not<bool>());
printVector(v2);
/*
类似的逻辑仿函数还有很多:
logical_and<T> 逻辑与
logical_or<T> 逻辑或
*/
}
int main()
{
test01();
return 0;
}
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 一生雾梦!
评论
ValineDisqus