cpp—提高
模板
两种模板机制:函数模板和类模板
模板函数
函数模板实现两个变量的交换
#include <iostream>
using namespace std;
template<class T>
void mySwap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
int main()
{
int a = 10;
int b = 20;
//1.自动类型转换
mySwap(a, b);
cout << a << endl << b << endl;
//2.显示类型推导
mySwap<int>(a, b);
cout << a << endl << b << endl;
return 0;
}
注意事项:
自动类型推导一定要推导一致的数据类型T
模板必须要确定出数据类型才可以使用
案例:数组排序
#include <iostream>
using namespace std;
template<class T>
void mySwap(T& a, T& b)
{
T temp = a;
a = b;
b = temp;
}
template<class T>
void mySort(T arr[], int n)
{
for (int i = 0; i < n; i++)
{
int index = i;
for (int j = i + 1; j < n; j++)
{
if (arr[index] > arr[j])
{
index = j;
}
}
if (index != i)
{
mySwap<T>(arr[index], arr[i]);
}
}
}
template<class T>
void myPrint(T arr[], int len)
{
for (int i = 0; i < len; i++)
{
cout << arr[i];
}
}
int main()
{
int arr1[] = { 5, 4, 3, 2, 1 };
int num1 = sizeof(arr1) / sizeof(int);
cout << sizeof(arr1) / sizeof(int) << endl;
mySort<int>(arr1, num1);
myPrint<int>(arr1, num1);
cout << endl;
char arr2[] = "tdpsu";
// char arr3[] = { 't', 'd', 'p', 's', 'u'};
int num2 = sizeof(arr2) / sizeof(char);
cout << sizeof(arr2) / sizeof(char) << endl;
mySort<char>(arr2, num2);
myPrint<char>(arr2, num2);
return 0;
}
构建字符数组的时候出现了遗留的问题:arr2和arr3是两种不同的初始化方式,但是呢在计算num的时候我发现它们大小相差1,arr2为6而arr3为5,那是因为arr2是用的字符串初始化的方式,它会在数组最后一个位置留下’\0’这个字符。
还有这里计算长度的方法:sizeof(变量)/sizeof(类型)是我在书写时没想到的
分析代码,这里我们写了三个函数的模板,有选择排序、交换和打印。注意调用模板函数的时候模板书写的位置,
在函数名和参数之间
。普通函数与函数模板的区别:
普通函数可以隐式类型转换,而函数模板不行;而普通函数不能显示指定类型而函数模板可以做到。
普通函数与函数模板的调用规则
1.如果函数模板和普通模板都能调用,优先调用普通函数—myPrint();
2.可以通过空模板参数列表强制调用函数模板—myPrint<>();
3.函数模板可以发生函数重载—参数个数,类型,顺序不同
4.如果函数模板可以产生更好的匹配 优先调用函数模板
模板函数的局限性
拿比较函数举例,如果使用模板函数,仅仅只能比较内置数据类型比如int、char之类的。但是当遇到自定义数据类型Person之类的话我们无法将两个对象之间进行比较,这要用到之前所提到的运算符重载。
#include <iostream>
using namespace std;
class Person
{
public:
Person(string name, int age)
{
m_age = age;
m_name = name;
}
string m_name;
int m_age;
};
template<class T>
bool myCompare(T& a, T& b)
{
if (a == b) return true;
else return false;
}
//利用具体化Person的版本实现代码,具体化优先调用
template<> bool myCompare(Person& p1, Person& p2)
{
if (p1.m_age == p2.m_age && p1.m_name == p2.m_name) return true;
else return false;
}
int main()
{
Person p1("tom", 12);
Person p2("tom", 12);
cout << myCompare(p1, p2);
return 0;
}
类模板
类模板何函数模板的区别
1.类模板没有自动类型推导的使用方式
2.类模板在模板参数列表中可以有默认参数
#include <iostream>
using namespace std;
template<class NameType, class AgeType = int>//可以有默认参数类型
class Person
{
public:
Person(NameType name, AgeType age)
{
m_name = name;
m_age = age;
}
NameType m_name;
AgeType m_age;
};
int main()
{
Person<string> p1("haha", 18);
// Person p2("haha", 18);不能自动类型推导
cout << p1.m_name << " " << p1.m_age << endl;
return 0;
}
类模板中成员函数创建时机
- 普通类中的成员函数一开始就可以创建
- 类模板中的成员函数在调用时才创建
由于类模板需要确定数据类型,所以只有在程序运行过程中确定数据类型之后才会创建类模板中的成员函数。
#include <iostream>
using namespace std;
class Person1
{
public:
void showPerson1()
{
cout << "showPerson1" << endl;
}
};
class Person2
{
public:
void showPerson2()
{
cout << "showPerson2" << endl;
}
};
template<class T>
class myClass
{
public:
void func1()
{
obj.showPerson1();
}
void func2()
{
obj.showPerson2();
}
T obj;
};
int main()
{
myClass<Person1> mc1;
mc1.func1();
myClass<Person2> mc2;
mc2.func2();
return 0;
}
类模板对象做函数参数
通常直接指定传入的类型—直接显示对象的数据类型
类模板与友元
针对于全局函数通常使用类内实现—直接在类内声明友元即可
#include <iostream>
using namespace std;
template<class T1, class T2>
class Person
{
friend void showPerson(Person<T1, T2>& p)
{
cout << p.m_name << " " << p.m_age;
}
public:
Person(T1 name, T2 age)
{
m_name = name;
m_age = age;
}
private:
T1 m_name;
T2 m_age;
};
int main()
{
Person<string, int> p("Tom", 19);
showPerson(p);
return 0;
}
类外实现挺复杂的…遇到了话就只用在类内实现这种写法吧…
STL
基本概念
STL(Standard Template Library标准模板库)
STL从广义上分为:容器、算法、迭代器
。容器和算法之间通过迭代器无缝衔接
STL几乎所有代码都采用了模板类或者模板函数
STL六大组件:容器、算法、迭代器、仿函数、适配器、空间配置器
常见容器
String容器
#include <iostream>
using namespace std;
int main()
{
//构造函数
cout << "构造函数模块:" << endl;
string s11;//默认构造
const char* str = "hello world";
string s12(str);//有参构造
string s13(s12);//拷贝构造
string s14(3, 'a');//初始化s4为aaa
cout << s12 << endl << s13 << endl << s14 << endl;
cout << "--------------------------------" << endl;
//赋值操作
cout << "赋值操作模块:" << endl;
string str21 = "hello world";
string str22 = str21;
string str23 = "a";
cout << str21 << endl << str22 << endl << str23 << endl;
string str24;
str24.assign("hello world");
string str25;
str25.assign(str21, 0, 7);//取出str21前7个字符给str25,从0开始 长度为7
string str26;
str26.assign(str25);//类似于string s1(s2);
string str27;
str27.assign(3, 'w');
cout << str24 << endl << str25 << endl << str26 << endl << str27 << endl;
//字符串拼接
cout << "---------------------------" << endl;
cout << "字符串拼接" << endl;
string str31 = "lzl";
str31 += "hao shuai";
string str32 = "hello world";
str31.append(str32, 0, 7);//同assgin函数类似,从0开始截取长度为7并且拼接到str31中
cout << str31 << endl << str32 << endl;
//查找和替换
cout << "---------------------------" << endl;
cout << "查找和替换" << endl;
string str41 = "abcdebcde";//find从左往右找,rfind从右往左找 找到就返回第一次出现的下标位置 没找到就返回-1
cout << str41.find("de") << endl << str41.rfind("de") << endl;
cout << str41.replace(5, 2, "1111") << endl;
//字符串比较
cout << "---------------------------" << endl;
cout << "字符串比较" << endl;
string str51 = "hello world";
string str52 = "hello world";
cout << str51.compare(str52) << endl;//从头往后一个一个比较等于返回0 大于返回1 小于返回-1
//字符串插入和删除
cout << "---------------------------" << endl;
cout << "字符串插入和删除" << endl;
string str61 = "lzl hao shuai aaa";
cout << str61.insert(4, "666 ") << endl;
cout << str61.insert(4, 3, 'b') << endl;
cout << str61.erase(4, 3) << endl;
//字串截取
cout << "---------------------------" << endl;
cout << "字串截取" << endl;
string str71 = "ebriejndfjk";
cout << str71.substr(3, 5) << endl;
return 0;
}
输出:
构造函数模块:
hello world
hello world
aaa
--------------------------------
赋值操作模块:
hello world
hello world
a
hello world
hello w
hello w
www
---------------------------
字符串拼接
lzlhao shuaihello w
hello world
---------------------------
查找和替换
3
7
abcde1111de
---------------------------
字符串比较
0
---------------------------
字符串插入和删除
lzl 666 hao shuai aaa
lzl bbb666 hao shuai aaa
lzl 666 hao shuai aaa
---------------------------
字串截取
iejnd
vector容器
类似于数组但区别于数组,数组是静态空间而vector容器可以动态扩展,vector容器的动态扩展并不是在原来基础上续借新空间,而是找更大的内存空间将原来的数据拷贝过来再添加数据,最后释放掉原来的空间。
vector容器的迭代器是支持随机访问的迭代器,可以后移多位。
#include <iostream>
#include <vector>
using namespace std;
void printVector(vector<int>& v)
{
for (vector<int>::iterator it = v.begin(); it != v.end(); it++)
{
cout << *it << " ";
}
cout << '\n';
}
int main()
{
cout << "构造函数" << endl;
//默认构造
vector<int> v1_1;
for (int i = 0; i < 10; i++)
{
v1_1.push_back(i);
}
printVector(v1_1);
//区间方式构造
vector<int> v1_2(v1_1.begin(), v1_1.end());
printVector(v1_2);
//n个elem方式构造
vector<int> v1_3(10, 100);
printVector(v1_3);
//拷贝构造
vector<int> v1_4(v1_1);
printVector(v1_4);
cout << "----------------------------" << endl;
//赋值操作
cout << "赋值操作" << endl;
vector<int> v2_1 = v1_1;
printVector(v2_1);
vector<int> v2_2;
v2_2.assign(v2_1.begin(), v2_1.end());
printVector(v2_2);
vector<int> v2_3;
v2_3.assign(10, 100);
printVector(v2_3);
cout << "----------------------------" << endl;
//容量和大小
cout << "容量和大小" << endl;
vector<int> v3_1 = v1_1;
printVector(v3_1);
if (v3_1.empty())
{
cout << "为空" << endl;
}
else
{
cout << "不为空" << endl;
cout << "容量为:" << v3_1.capacity() << endl;
cout << "大小为:" << v3_1.size() << endl;
}
v3_1.resize(14, 1);//修改大小,空余部分补1
printVector(v3_1);
cout << "resize扩大之后:" << "容量为:" << v3_1.capacity() << " 大小为:" << v3_1.size() << endl;
v3_1.resize(8);
printVector(v3_1);
cout << "resize缩小之后:" << "容量为:" << v3_1.capacity() << " 大小为:" << v3_1.size() << endl;
cout << "----------------------------" << endl;
//插入和删除
cout << "插入和删除" << endl;
vector<int> v4_1 = v1_1;
v4_1.push_back(100);
cout << "尾插后输出:";
printVector(v4_1);
v4_1.pop_back();
cout << "尾删后输出:";
printVector(v4_1);
v4_1.insert(v4_1.begin(), 666);//在指定迭代器位置插入一个数
cout << "在指定迭代器(头部)插入后:";
printVector(v4_1);
v4_1.insert(v4_1.begin(), 2, 111);//在指定迭代器位置插入2个111
cout << "在指定迭代器(头部)插入2个111后:";
printVector(v4_1);
v4_1.erase(v4_1.end()-1);//删除指定迭代器的位置的元素
cout << "erase删除最后一个元素后:";
printVector(v4_1);
//v4_1.erase(v4_1.begin(), v4_1.end());删除所有元素
//v4_1.clear();删除所有元素
cout << "----------------------------" << endl;
//容器互换 让resize之后收缩内存
cout << "容器互换" << endl;
vector<int> v5_1;
for (int i = 0; i < 10000; i++)
{
v5_1.push_back(i);
}
cout << "容量为:" << v5_1.capacity() << " 大小为:" << v5_1.size() << endl;
v5_1.resize(5);
cout << "resize之后容量为:" << v5_1.capacity() << " 大小为:" << v5_1.size() << "浪费空间数量:" << v5_1.capacity() - v5_1.size() << endl;
vector<int>(v5_1).swap(v5_1);//匿名对象方法,创建匿名对象时是按照v5_1实际的size创建的,语句执行完之后匿名对象由操作系统删除
cout << "执行vector<int>(v5_1).swap(v5_1)后:" << "resize之后容量为:" << v5_1.capacity() << " 大小为:" << v5_1.size() << "浪费空间数量:" << v5_1.capacity() - v5_1.size() << endl;
cout << "----------------------------" << endl;
//reserve预留空间减少内存分配的次数
cout << "预留空间" << endl;
vector<int> v6_1, v6_2;
v6_2.reserve(100000);
int num1 = 0, num2 = 0;
int* p1 = NULL, * p2 = NULL;
for (int i = 0; i < 100000; i++)
{
v6_1.push_back(i);
v6_2.push_back(i);
if (p1 != &v6_1[0])
{
p1 = &v6_1[0];
num1++;
}
if (p2 != &v6_2[0])
{
p2 = &v6_2[0];
num2++;
}
}
cout << "未预留分配:" << num1 << "次" << endl
<< "预留分配:" << num2 << "次" << endl;
return 0;
}
输出:
构造函数
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
100 100 100 100 100 100 100 100 100 100
0 1 2 3 4 5 6 7 8 9
----------------------------
赋值操作
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9
100 100 100 100 100 100 100 100 100 100
----------------------------
容量和大小
0 1 2 3 4 5 6 7 8 9
不为空
容量为:10
大小为:10
0 1 2 3 4 5 6 7 8 9 1 1 1 1
resize扩大之后:容量为:15 大小为:14
0 1 2 3 4 5 6 7
resize缩小之后:容量为:15 大小为:8
----------------------------
插入和删除
尾插后输出:0 1 2 3 4 5 6 7 8 9 100
尾删后输出:0 1 2 3 4 5 6 7 8 9
在指定迭代器(头部)插入后:666 0 1 2 3 4 5 6 7 8 9
在指定迭代器(头部)插入2个111后:111 111 666 0 1 2 3 4 5 6 7 8 9
erase删除最后一个元素后:111 111 666 0 1 2 3 4 5 6 7 8
----------------------------
容器互换
容量为:12138 大小为:10000
resize之后容量为:12138 大小为:5浪费空间数量:12133
执行vector<int>(v5_1).swap(v5_1)后:resize之后容量为:5 大小为:5浪费空间数量:0
----------------------------
预留空间
未预留分配:30次
预留分配:1次
deque容器
称为双端数组,可以对头端进行插入删除操作,相比于vector容器,deque容器对头部插入和删除要更快,但vector容器访问元素时的速度会比deque快。
#include <iostream>
#include <deque>
#include <vector>
#include <algorithm>
using namespace std;
//把输出设置为只读状态 iterator改成const_iterator
void printDeque(const deque<int>& d)
{
for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++)
{
cout << *it << " ";
}
cout << '\n';
}
int main()
{
cout << "构造函数" << endl;
deque<int> d1_1;//默认构造
for (int i = 0; i < 5; i++)
{
d1_1.push_back(i);
}
printDeque(d1_1);
deque<int> d1_2(d1_1.begin(), d1_1.end());
printDeque(d1_2);
deque<int> d1_3(3, 10);
printDeque(d1_3);
deque<int> d1_4(d1_3);
printDeque(d1_4);
cout << "-----------------------" << endl;
cout << "赋值操作" << endl;
deque<int> d2_1 = d1_1;
printDeque(d2_1);
deque<int> d2_2;
d2_2.assign(d1_1.begin(), d1_1.end());
printDeque(d2_2);
deque<int> d2_3;
d2_3.assign(3, 100);
printDeque(d2_3);
cout << "-----------------------" << endl;
cout << "大小操作" << endl;
deque<int> d3_1 = d1_1;
if (d3_1.empty())
{
cout << "为空" << endl;
}
else
{
cout << "size为:" << d3_1.size() << endl;//没有capacity
}
d3_1.resize(10, 1);
cout << "resize之后:";
printDeque(d3_1);
cout << "size为:" << d3_1.size() << endl;
cout << "-----------------------" << endl;
cout << "插入和删除" << endl;
deque<int> d4_1 = d1_1;
//比vector多了前插和前删,所以只展示前插和前删
d4_1.push_front(100);
cout << "头插100后:";
printDeque(d4_1);
d4_1.pop_front();
cout << "头删后:";
printDeque(d4_1);
//插入指定位置
d4_1.insert(d4_1.end(), 3, 100);//在尾部插入3个100,中间的参数可以省略,省略就默认插入一个100
printDeque(d4_1);
d4_1.insert(d4_1.end(), d4_1.begin(), d4_1.end());//相当于复制一遍追加在末尾
printDeque(d4_1);
//清空所有数据
// d4_1.clear();
// d4_1.erase(d4_1.begin(), d4_1.end());
d4_1.erase(d4_1.begin());
printDeque(d4_1);
cout << "-----------------------" << endl;
cout << "数据存储" << endl;
cout << "d4_1[3]取出下标为3的数:" << d4_1[3] << " "
<< "front取出第一个元素" << d4_1.front() << " "
<< "back取出最后一个元素" << d4_1.back() << endl;
cout << "-----------------------" << endl;
cout << "排序" << endl;
sort(d4_1.begin(), d4_1.end());
printDeque(d4_1);
return 0;
}
输出:
构造函数
0 1 2 3 4
0 1 2 3 4
10 10 10
10 10 10
-----------------------
赋值操作
0 1 2 3 4
0 1 2 3 4
100 100 100
-----------------------
大小操作
size为:5
resize之后:0 1 2 3 4 1 1 1 1 1
size为:10
-----------------------
插入和删除
头插100后:100 0 1 2 3 4
头删后:0 1 2 3 4
0 1 2 3 4 100 100 100
0 1 2 3 4 100 100 100 0 1 2 3 4 100 100 100
1 2 3 4 100 100 100 0 1 2 3 4 100 100 100
-----------------------
数据存储
d4_1[3]取出下标为3的数:4 front取出第一个元素1 back取出最后一个元素100
-----------------------
排序
0 1 1 2 2 3 3 4 4 100 100 100 100 100 100
评委打分案例
#include <iostream>
#include <vector>
#include <deque>
#include <algorithm>
#include <numeric>
using namespace std;
class Person
{
public:
Person(string name, double score)
{
this->m_Name = name;
this->m_Score = score;
}
string m_Name;
double m_Score;
};
void createPerson(vector<Person>& v)
{
string nameSeed = "ABCDE";
for (int i = 0; i < 5; i++)
{
string name = "选手";
name += nameSeed[i];//字符串重载了[]运算符,可以分别取出ABCDE
Person p(name, 0);
v.push_back(p);
}
}
void setScore(vector<Person>& v)
{
//10个评委打分
for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
{
deque<int> d;
for (int i = 0; i < 10; i++)
{
int tscore = rand() % 41 + 60;//60~100
d.push_back(tscore);
}
//去除最高分和最低分
sort(d.begin(), d.end());
d.pop_back();
d.pop_front();
//求平均分
double avg = accumulate(d.begin(), d.end(), 0)/d.size();
//存入
it->m_Score = avg;
}
}
void showScore(vector<Person>& v)
{
for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
{
cout << it->m_Name << " " << it->m_Score << endl;
}
}
int main()
{
//随机数种子
srand((unsigned int)time(NULL));
//创建5名选手
vector<Person> v;
createPerson(v);
//for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
//{
// cout << (*it).m_Name << " " << (*it).m_Score << endl;
//}
//给5名选手打分
setScore(v);
//for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
//{
// cout << (*it).m_Name << " " << (*it).m_Score << endl;
//}
//显示最后得分
showScore(v);
return 0;
}
输出:
选手A 83
选手B 80
选手C 80
选手D 81
选手E 74
这里运用到了前面所学的3个容器string、vector和deque
string:首先考虑到输出的”选手“两个字是重复的,改变的只有ABCDE编号,所以用循环和字符串拼接就达到了这样的效果,取出字符串中单个字符就使用重载的[]索引获取对应字符。
vector:这里用vector容器主要用来存储选手数据,以便初始化和显示数据
deque:考虑到它的特点是双端数组,可以对其进行头插尾插和头删尾删。所以这里用deque容器来对评委打出数据进行存储。如何删去最后高分和最低分?可以先调用sort函数将deque容器里的数据进行排序,sort默认是升序排序,当然,除去最高分和最低分只需要pop_fornt和pop_back操作就行了。再调用accumulate函数计算deque容器中的总和最后于d.size()相除得到平均分。注意accumulate中有三个参数分别为:初始迭代器、结束迭代器和从num开始加起,这里从0开始加所以第三个参数为0。
还有生成随机数的写法这里生成的是60100的随机数就用rand()%41+60,rand()%41的范围在040,加上60即左右两边均加上60就得到60~100了。这还不够,因为每次生成的随机数是一样的,想要生成不一样的随机数需要加上随机数种子srand((unsigned int)time(NULL));
stack容器
是一种先进先出的栈结构
#include <iostream>
#include <stack>
using namespace std;
int main()
{
//stack的基本接口
stack<int> s1;
for (int i = 0; i < 5; i++)
{
//入栈push
s1.push(i);
}
cout << "取栈顶元素top:" << s1.top() << endl;
s1.pop();
cout << "删除栈顶之后的top:" << s1.top() << endl;
stack<int> s2 = s1;//重载等号
stack<int> s3(s2);//拷贝构造
cout << "是否为空empty(空为1非空为0):" << s2.empty() << endl;
cout << "s3的size为多少:" << s3.size() << endl;
return 0;
}
输出:
取栈顶元素top:4
删除栈顶之后的top:3
是否为空empty(空为1非空为0):0
s3的size为多少:4
queue容器
#include <iostream>
#include <queue>
using namespace std;
int main()
{
queue<int> q;
for (int i = 0; i < 5; i++)
{
q.push(i);
}
cout << "对头:" << q.front() << "队尾:" << q.back() << endl;
q.pop();
cout << "pop删除后对头:" << q.front() << "队尾:" << q.back() << endl;
cout << "是否为空(1为空0为非空)" << q.empty() << endl;
cout << "size为:" << q.size() << endl;
//赋值操作
queue<int> q2(q);
queue<int> q3 = q2;
return 0;
}
输出:
对头:0队尾:4
pop删除后对头:1队尾:4
是否为空(1为空0为非空)0
size为:4
注意:stack容器和queue容器都不能进行遍历操作!!!
list容器
可以理解为封装起来的双向循环链表
#include <iostream>
#include <list>
using namespace std;
void printList(const list<int>& l)
{
for (list<int>::const_iterator it = l.begin(); it != l.end(); it++)
{
cout << *it << " ";
}
cout << '\n';
}
int main()
{
cout << "构造函数" << endl;
list<int> l1;
for (int i = 0; i < 5; i++)
{
l1.push_back(i * 10);
}
printList(l1);
list<int> l2(l1.begin(), l1.end());
printList(l2);
list<int> l3(l2);
printList(l3);
list<int> l4(10, 1000);
printList(l4);
cout << "-------------------------" << endl;
cout << "赋值操作" << endl;
list<int> l5 = l4;
printList(l5);
list<int> l6;
l6.assign(l1.begin(), l1.end());
printList(l6);
list<int> l7;
l7.assign(3, 10);
printList(l7);
cout << "分别输出l6和l7:" << endl;
printList(l6);
printList(l7);
l6.swap(l7);
cout << "交换l6和l7后分别输出l6和l7:" << endl;
printList(l6);
printList(l7);
cout << "-------------------------" << endl;
cout << "大小操作" << endl;
cout << "l7的size为:" << l7.size() << " 是否为空(非空为0空为1):" << l7.empty() << endl;
l7.resize(10);
cout << "resize扩容之后输出l7,默认填0:" << endl;
printList(l7);
return 0;
}
set容器
set和multiset的区别:set不能存放重复的数据,而multiset可以存放重复的数据并排序
#include <iostream>
#include <set>
#include <algorithm>
#include <functional>
using namespace std;
void Myprint(int val)
{
cout << val << " ";
}
class Person
{
public:
Person(int age, string name)
{
this->m_age = age;
this->m_name = name;
}
int m_age;
string m_name;
};
//自己写一个谓词
class Greater_age
{
public:
bool operator()(const Person& p1, const Person& p2) const
{
return p1.m_age > p2.m_age;
}
};
void test01()
{
set<Person, Greater_age> s;
Person p1(10, "lzl");
Person p2(15, "lxc");
Person p3(19, "xrg");
Person p4(100, "mgj");
s.insert(p1);
s.insert(p2);
s.insert(p3);
s.insert(p4);
for (set<Person, Greater_age>::iterator it = s.begin(); it != s.end(); it++)
{
cout << "年龄:" << it->m_age << " 姓名:" << it->m_name << endl;
}
}
int main()
{
test01();
return 0;
}
输出:
年龄:100 姓名:mgj
年龄:19 姓名:xrg
年龄:15 姓名:lxc
年龄:10 姓名:lzl
set容器其主要作用是插入数据时就会将其进行排序,底层是以二叉树实现的,基本的构造函数、赋值、插入删除操作就不展示了,可以去cppreferrence官网查
map容器
分为map和multimap,类似于set和multiset。map不能插入重复key值而multimap可以插入重复key值。所有元素根据key值自动排序
#include <iostream>
#include <map>
using namespace std;
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 << '\n';
}
int main()
{
cout << "构造函数:" << endl;
map<int, int> m;
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>(5, 50));
m.insert(pair<int, int>(4, 40));
printMap(m);
// map<int, int> m1(m);
// map<int, int> m2 = m1;
cout << "--------------------------" << endl;
cout << "大小和交换" << endl;
cout << "size为:" << m.size() << " 是否为空(0为非空1为空)" << m.empty() << endl;
cout << "--------------------------" << endl;
cout << "删除" << endl;
m.erase(3);
cout << "删除键值3之后:" << endl;
printMap(m);
cout << "--------------------------" << endl;
cout << "查找和统计:" << endl;
map<int, int>::iterator it = m.find(50);//返回的是迭代器
if (it != m.end())
{
cout << "查到了key:" << it->first << " value:" << it->second << endl;
}
else
{
cout << "没查到" << endl;
}
cout << "统计:" << m.count(2) << endl;//按照key统计
return 0;
}
输出:
构造函数:
key: 1 value: 10
key: 2 value: 20
key: 3 value: 30
key: 4 value: 40
key: 5 value: 50
--------------------------
大小和交换
size为:5 是否为空(0为非空1为空)0
--------------------------
删除
删除键值3之后:
key: 1 value: 10
key: 2 value: 20
key: 4 value: 40
key: 5 value: 50
--------------------------
查找和统计:
没查到
统计:1
由于set容器和map容器都是以二叉树为底层原理构建的容器,在插入数据的时候会自动的进行排序,但是如果对于自定义数据类型的话一定要写仿函数规定出你想要的排序方式,然后加入到对应的模板参数列表中。
自定义数据类型的排序
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
void Myprint(int val)
{
cout << val << " ";
}
class Person
{
public:
Person(int age, string name)
{
this->m_age = age;
this->m_name = name;
}
int m_age;
string m_name;
};
//自己写一个谓词
class Greater_age
{
public:
bool operator()(const Person& p1, const Person& p2)
{
return p1.m_age > p2.m_age;
}
};
void test01()
{
vector<Person> v;
Person p1(10, "lzl");
Person p2(15, "lxc");
Person p3(29, "xrg");
Person p4(100, "mgj");
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
sort(v.begin(), v.end(), Greater_age());//#include<functional>
// sort(v.begin(), v.end());//没有谓词默认升序
// for_each(v.begin(), v.end(), Myprint);//遍历算法
for (vector<Person>::iterator it = v.begin(); it != v.end(); it++)
{
cout << "年龄:" << it->m_age << " 姓名:" << it->m_name << endl;
}
}
int main()
{
test01();
return 0;
}
输出:
年龄:100 姓名:mgj
年龄:29 姓名:xrg
年龄:15 姓名:lxc
年龄:10 姓名:lzl
谓词
返回bool类型的仿函数称为谓词
如果operator()接受一个参数,那么叫做一元谓词
如果operator()接受两个参数,那么叫做二元谓词
- 一元谓词
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>
using namespace std;
void Myprint(int val)
{
cout << val << " ";
}
class Person
{
public:
Person(int age, string name)
{
this->m_age = age;
this->m_name = name;
}
int m_age;
string m_name;
};
class Greater_20
{
public:
bool operator()(const Person& p)
{
if (p.m_age > 20)
{
return true;
}
else
{
return false;
}
}
};
void test01()
{
vector<Person> v;
Person p1(10, "lzl");
Person p2(15, "lxc");
Person p3(29, "xrg");
Person p4(100, "mgj");
v.push_back(p1);
v.push_back(p2);
v.push_back(p3);
v.push_back(p4);
vector<Person>::iterator it = find_if(v.begin(), v.end(), Greater_20());
cout << "姓名:" << it->m_name << " 年龄:" << it->m_age << endl;
}
int main()
{
test01();
return 0;
}
输出:
姓名:xrg 年龄:29
- 二元谓词参见上面的自定义数据类型的排序中的谓词Greater_age