C++泛型编程(C++模板)、STL技术详解

大理寺少卿 · · 编程&逆向技术交流
1

本文共计1144个字,预计阅读时长4.6分钟。

# C++提高编程 * 本阶段主要针对C++==泛型编程==和==STL==技术做详细讲解,探讨C++更深层的使用 ## 1 模板 ### 1.1 模板的概念 模板就是建立**通用的模具**,大大**提高复用性** 例如生活中的模板 一寸照片模板: 13_41_08_81983 PPT模板: 13_41_26_85135 13_41_36_46703 模板的特点: * 模板不可以直接使用,它只是一个框架 * 模板的通用并不是万能的 ### 1.2 函数模板 * C++另一种编程思想称为 ==泛型编程== ,主要利用的技术就是模板 * C++提供两种模板机制?*函数模板**和**类模板** #### 1.2.1 函数模板语法 函数模板作用: 建立一个通用函数,其函数返回值类型和形参类型可以不具体制定,用一个**虚拟的类型**来代表。 **语法:** ```C++ template<typename T> 函数声明或定义 ``` **解释:** template --- 声明创建模板 typename --- 表面其后面的符号是一种数据类型,可以用class代替 T --- 通用的数据类型,名称可以替换,通常为大写字母 **示例:** ```C++ //交换整型函数 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> 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); cout <<"a = " <// 也可以替换成typename //利用选择排序,进行对数组从大到小的排序 void mySort(T arr[], int len) { for (int i = 0; i b) { ... } } ``` 在上述代码中,如果T的数据类型传入的是像Person这样的自定义数据类型,也无法正常运行 因此C++为了解决这种问题,提供模板的重载,可以为这些**特定的类型**提供**具体化的模板** **示例:** ```C++ #include<iostream> using namespace st? #include <string> class Person { public: Person(string name, int age) { this->m_Name = name; this->m_Age = age; } string m_Name; int m_Age; }; //普通函数模板 template<class T> bool myCompare(T& a, T& b) { if (a == b) { return true; } else { return false; } } //具体化,显示具体化的原型和定意思以template<>开头,并通过名称来指出类型 //具体化优先于常规模板 template<>bool myCompare(Person &p1, Person &p2) { if ( p1.m_Name == p2.m_Name && p1.m_Age == p2.m_Age) { return true; } else { return false; } } void test01() { int a = 10; int b = 20; //内置数据类型可以直接使用通用的函数模板 bool ret = myCompare(a, b); if (ret) { cout <<"a == b " < class Person { public: Person(NameType name, AgeType age) { this->mName = name; this->mAge = age; } void showPerson() { cout <<"name: " < class Person { public: Person(NameType name, AgeType age) { this->mName = name; this->mAge = age; } void showPerson() { cout <<"name: " <p("猪八戒", 999); //类模板中的模板参数列表 可以指定默认参数 p.showPerson(); } int main() { test01(); test02(); system("pause"); return 0; } ``` 总结: * 类模板使用只能用显示指定类型方式 * 类模板中的模板参数列表可以有默认参数 #### 1.3.3 类模板中成员函数创建时机 类模板中成员函数和普通类中成员函数创建时机是有区别的: * 普通类中的成员函数一开始就可以创建 * 类模板中的成员函数在调用时才创建 **示例:** ```C++ class Person1 { public: void showPerson1() { cout <<"Person1 show" <m; m.fun1(); //m.fun2();//编译会出错,说明函数调用才会去创建成员函数 } int main() { test01(); system("pause"); return 0; } ``` 总结:类模板中的成员函数并不是一开始就创建的,在调用时才去创建 #### 1.3.4 类模板对象做函数参数 学习目标: * 类模板实例化出的对象,向函数传参的方式 一共有三种传入方式: 1. 指定传入的类型 --- 直接显示对象的数据类型 2. 参数模板化 --- 将对象中的参数变为模板进行传递 3. 整个类模板化 --- 将这个对象类型 模板化进行传递 **示例:** ```C++ #include <string> //类模板 template<class NameType, class AgeType = int> class Person { public: Person(NameType name, AgeType age) { this->mName = name; this->mAge = age; } void showPerson() { cout <<"name: " <&p) { p.showPerson(); } void test01() { Person <string, int >p("孙悟空", 100); printPerson1(p); } //2、参数模板化 template <class T1, class T2> void printPerson2(Person<T1, T2>&p) { p.showPerson(); cout <<"T1的类型为: " <//必须指定一个类型 { }; void test01() { Son c; } //类模板继承类模板 ,可以用T2指定父类中的T类型 template<class T1, class T2> class Son2 :public Base<T2> { public: Son2() { cout <child1; } int main() { test01(); test02(); system("pause"); return 0; } ``` 总结:如果父类是类模板,子类需要指定出父类中T的数据类型 #### 1.3.6 类模板成员函数类外实现 学习目标:能够掌握类模板中的成员函数类外实现 **示例:** ```C++ #include <string> //类模板中成员函数类外实现 template<class T1, class T2> class Person { public: //成员函数类内声明 Person(T1 name, T2 age); void showPerson(); public: T1 m_Name; T2 m_Age; }; //构造函数 类外实现 template<class T1, class T2> Person<T1, T2>::Person(T1 name, T2 age) { this->m_Name = name; this->m_Age = age; } //成员函数 类外实现 template<class T1, class T2> void Person<T1, T2>::showPerson() { cout <<"姓名: " <p("Tom", 20); p.showPerson(); } int main() { test01(); system("pause"); return 0; } ``` 总结:类模板中成员函数类外实现时,需要加上模板参数列表 #### 1.3.7 类模板分文件编写 学习目标: * 掌握类模板成员函数分文件编写产生的问题以及解决方式 问题: * 类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到 解决: * 解决方式1:直接包含.cpp源文件 * 解决方式2:将声明和实现写到同一个文件中,并更改后缀名为.hpp,hpp是约定的名称,并不是强制 **示例:** person.hpp中代码: ```C++ #pragma once #include <iostream> using namespace st? #include <string> template<class T1, class T2> class Person { public: Person(T1 name, T2 age); void showPerson(); public: T1 m_Name; T2 m_Age; }; //构造函数 类外实现 template<class T1, class T2> Person<T1, T2>::Person(T1 name, T2 age) { this->m_Name = name; this->m_Age = age; } //成员函数 类外实现 template<class T1, class T2> void Person<T1, T2>::showPerson() { cout <<"姓名: " <p("Tom", 10); p.showPerson(); } int main() { test01(); system("pause"); return 0; } ``` 总结:主流的解决方式是第二种,将类模板成员函数写到一起,并将后缀名改为.hpp #### 1.3.8 类模板与友元 学习目标: * 掌握类模板配合友元函数的类内和类外实现 全局函数类内实现 - 直接在类内声明友元即可 全局函数类外实现 - 需要提前让编译器知道全局函数的存在 **示例:** ```C++ #include <string> //2、全局函数配合友元 类外实现 - 先做函数模板声明,下方在做函数模板定义,在做友元 template<class T1, class T2>class Person; //如果声明了函数模板,可以将实现写到后面,否则需要将实现体写到类的前面让编译器提前看到 //template<class T1, class T2>void printPerson2(Person<T1, T2>& p); template<class T1, class T2> void printPerson2(Person<T1, T2>& p) { cout <<"类外实现 ---- 姓名: " <& p) { cout <<"姓名: " <& p); public: Person(T1 name, T2 age) { this->m_Name = name; this->m_Age = age; } private: T1 m_Name; T2 m_Age; }; //1、全局函数在类内实现 void test01() { Person <string, int >p("Tom", 20); printPerson(p); } //2、全局函数在类外实现 void test02() { Person <string, int >p("Jerry", 30); printPerson2(p); } int main() { //test01(); test02(); system("pause"); return 0; } ``` 总结:建议全局函数做类内实现,用法简单,而且编译器可以直接识别 #### 1.3.9 类模板案例 案例描述: 实现一个通用的数组类,要求如下: * 可以对内置数据类型以及自定义数据类型的数据进行存储 * 将数组中的数据存储到堆区 * 构造函数中可以传入数组的容量 * 提供对应的拷贝构造函数以及operator=防止浅拷贝问题 * 提供尾插法和尾删法对数组中的数据进行增加和删除 * 可以通过下标的方式访问数组中的元素 * 可以获取数组中当前元素个数和数组的容量 **示例:** myArray.hpp中代码 ```C++ #pragma once #include <iostream> using namespace st? template<class T> class MyArray { public: //构造函数 MyArray(int capacity) { this->m_Capacity = capacity; this->m_Size = 0; pAddress = new T[this->m_Capacity]; } //拷贝构造 MyArray(const MyArray & arr) { this->m_Capacity = arr.m_Capacity; this->m_Size = arr.m_Size; this->pAddress = new T[this->m_Capacity]; for (int i = 0; i array1(10); for (int i = 0; i <10; i++) { array1.Push_back(i); } cout <<"array1打印输出:" <array2(array1); array2.Pop_back(); cout <<"array2打印输出:" <pArray(10); Person p1("孙悟空", 30); Person p2("韩信", 20); Person p3("妲己", 18); Person p4("王昭君", 15); Person p5("赵云", 24); //插入数据 pArray.Push_back(p1); pArray.Push_back(p2); pArray.Push_back(p3); pArray.Push_back(p4); pArray.Push_back(p5); printPersonArray(pArray); cout <<"pArray的大小:" <v; //向容器中放数据 v.push_back(10); v.push_back(20); v.push_back(30); v.push_back(40); //每一个容器都有自己的迭代器,迭代器是用来遍历容器中的元素 //v.begin()返回迭代器,这个迭代器指向容器中第一个数据 //v.end()返回迭代器,这个迭代器指向容器元素的最后一个元素的下一个位置 //vector<int>::iterator 拿到vector<int>这种容器的迭代器类型 vector<int>::iterator pBegin = v.begin(); vector<int>::iterator pEnd = v.end(); //第一种遍历方式: while (pBegin != pEnd) { cout <<*pBegin <v; //创建数据 Person p1("aaa", 10); Person p2("bbb", 20); Person p3("ccc", 30); Person p4("ddd", 40); Person p5("eee", 50); 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).mName <<" Age:" <<(*it).mAge <v; //创建数据 Person p1("aaa", 10); Person p2("bbb", 20); Person p3("ccc", 30); Person p4("ddd", 40); Person p5("eee", 50); 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++) { Person * p = (*it); cout <<"Name:" <> 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); } //将容器元素插入到vector v中 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++) { for (vector<int>::iterator vit = (*it).begin(); vit != (*it).end(); vit++) { cout <<*vit <<" "; } cout <返回 1 <返回 -1 **函数原型:** * `int compare(const string &s) const; ` //与字符串s比较 * `int compare(const char *s) const;` //与字符串s比较 **示例:** ```C++ //字符串比较 void test01() { string s1 = "hello"; string s2 = "aello"; int ret = s1.compare(s2); if (ret == 0) { cout <<"s1 等于 s2" <0) { cout <<"s1 大于 s2" <v1; //无参构造 for (int i = 0; i <10; i++) { v1.push_back(i); } printVector(v1); vector<int>v2(v1.begin(), v1.end()); printVector(v2); vector<int>v3(10, 100); printVector(v3); vector<int>v4(v3); printVector(v4); } int main() { test01(); system("pause"); return 0; } ``` **总结:**vector的多种构造方式没有可比性,灵活使用即可 #### 3.2.3 vector赋值操作 **功能描述:** * 给vector容器进行赋值 **函数原型:** * `vector& operator=(const vector &vec);`//重载等号操作符 * `assign(beg, end);` //将[beg, end)区间中的数据拷贝赋值给本身。 * `assign(n, elem);` //将n个elem拷贝赋值给本身。 **示例:** ```C++ #include <vector> void printVector(vector<int>& v) { for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout <<*it <<" "; } cout <v1; //无参构造 for (int i = 0; i <10; i++) { v1.push_back(i); } printVector(v1); vector<int>v2; v2 = v1; printVector(v2); vector<int>v3; v3.assign(v1.begin(), v1.end()); printVector(v3); vector<int>v4; v4.assign(10, 100); printVector(v4); } int main() { test01(); system("pause"); return 0; } ``` 总结: vector赋值方式比较简单,使用operator=,或者assign都可以 #### 3.2.4 vector容量和大小 **功能描述:** * 对vector容器的容量和大小操作 **函数原型:** * `empty(); ` //判断容器是否为空 * `capacity();` //容器的容量 * `size();` //返回容器中元素的个数 * `resize(int num);` //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。 ​ //如果容器变短,则末尾超出容器长度的元素被删除。 * `resize(int num, elem);` //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。 ​ //如果容器变短,则末尾超出容器长度的元素被删除 **示例:** ```C++ #include <vector> void printVector(vector<int>& v) { for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout <<*it <<" "; } cout <v1; for (int i = 0; i <10; i++) { v1.push_back(i); } printVector(v1); if (v1.empty()) { cout <<"v1为空" <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()); v1.clear(); printVector(v1); } int main() { test01(); system("pause"); return 0; } ``` 总结: * 尾插 --- push_back * 尾删 --- pop_back * 插入 --- insert (位置迭代器) * 删除 --- erase (位置迭代器) * 清空 --- clear #### 3.2.6 vector数据存取 **功能描述:** * 对vector中的数据的存取操作 **函数原型:** * `at(int idx); ` //返回索引idx所指的数据 * `operator[]; ` //返回索引idx所指的数据 * `front(); ` //返回容器中第一个数据元素 * `back();` //返回容器中最后一个数据元素 **示例:** ```C++ #include <vector> void test01() { vector<int>v1; for (int i = 0; i <10; i++) { v1.push_back(i); } for (int i = 0; i 0; i--) { v2.push_back(i); } printVector(v2); //互换容器 cout <<"互换后" <v; for (int i = 0; i <100000; i++) { v.push_back(i); } cout <<"v的容量为:" <v; //预留空间 v.reserve(100000); int num = 0; int* p = NULL; for (int i = 0; i <100000; i++) { v.push_back(i); if (p != &v[0]) { p = &v[0]; num++; } } cout <<"num:" <d1; //无参构造函数 for (int i = 0; i <10; i++) { d1.push_back(i); } printDeque(d1); deque<int>d2(d1.begin(),d1.end()); printDeque(d2); deque<int>d3(10,100); printDeque(d3); deque<int>d4 = d3; printDeque(d4); } int main() { test01(); system("pause"); return 0; } ``` **总结:**deque容器和vector容器的构造方式几乎一致,灵活使用即可 #### 3.3.3 deque赋值操作 **功能描述:** * 给deque容器进行赋值 **函数原型:** * `deque& operator=(const deque &deq); ` //重载等号操作符 * `assign(beg, end);` //将[beg, end)区间中的数据拷贝赋值给本身。 * `assign(n, elem);` //将n个elem拷贝赋值给本身。 **示例:** ```C++ #include <deque> void printDeque(const deque<int>& d) { for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) { cout <<*it <<" "; } cout <d1; for (int i = 0; i <10; i++) { d1.push_back(i); } printDeque(d1); deque<int>d2; d2 = d1; printDeque(d2); deque<int>d3; d3.assign(d1.begin(), d1.end()); printDeque(d3); deque<int>d4; d4.assign(10, 100); printDeque(d4); } int main() { test01(); system("pause"); return 0; } ``` 总结:deque赋值操作也与vector相同,需熟练掌握 #### 3.3.4 deque大小操作 **功能描述:** * 对deque容器的大小进行操作 **函数原型:** * `deque.empty();` //判断容器是否为空 * `deque.size();` //返回容器中元素的个数 * `deque.resize(num);` //重新指定容器的长度为num,若容器变长,则以默认值填充新位置。 ​ //如果容器变短,则末尾超出容器长度的元素被删除。 * `deque.resize(num, elem);` //重新指定容器的长度为num,若容器变长,则以elem值填充新位置。 ​ //如果容器变短,则末尾超出容器长度的元素被删除。 **示例:** ```C++ #include <deque> void printDeque(const deque<int>& d) { for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) { cout <<*it <<" "; } cout <d1; for (int i = 0; i <10; i++) { d1.push_back(i); } printDeque(d1); //判断容器是否为空 if (d1.empty()) { cout <<"d1为空!" <? //尾插 d.push_back(10); d.push_back(20); //头插 d.push_front(100); d.push_front(200); printDeque(d); //尾删 d.pop_back(); //头删 d.pop_front(); printDeque(d); } //插入 void test02() { deque<int>? d.push_back(10); d.push_back(20); d.push_front(100); d.push_front(200); printDeque(d); d.insert(d.begin(), 1000); printDeque(d); d.insert(d.begin(), 2,10000); printDeque(d); deque<int>d2; d2.push_back(1); d2.push_back(2); d2.push_back(3); d.insert(d.begin(), d2.begin(), d2.end()); printDeque(d); } //删除 void test03() { deque<int>? d.push_back(10); d.push_back(20); d.push_front(100); d.push_front(200); printDeque(d); d.erase(d.begin()); printDeque(d); d.erase(d.begin(), d.end()); d.clear(); printDeque(d); } int main() { //test01(); //test02(); test03(); system("pause"); return 0; } ``` 总结: * 插入和删除提供的位置是迭代器! * 尾插 --- push_back * 尾删 --- pop_back * 头插 --- push_front * 头删 --- pop_front #### 3.3.6 deque 数据存取 **功能描述:** * 对deque 中的数据的存取操作 **函数原型:** - `at(int idx); ` //返回索引idx所指的数据 - `operator[]; ` //返回索引idx所指的数据 - `front(); ` //返回容器中第一个数据元素 - `back();` //返回容器中最后一个数据元素 **示例:** ```C++ #include <deque> void printDeque(const deque<int>& d) { for (deque<int>::const_iterator it = d.begin(); it != d.end(); it++) { cout <<*it <<" "; } cout <? d.push_back(10); d.push_back(20); d.push_front(100); d.push_front(200); for (int i = 0; i ? d.push_back(10); d.push_back(20); d.push_front(100); d.push_front(200); printDeque(d); sort(d.begin(), d.end()); printDeque(d); } int main() { test01(); system("pause"); return 0; } ``` 总结:sort算法非常实用,使用时包含头文件 algorithm即可 ### 3.4 案例-评委打分 #### 3.4.1 案例描述 有5名选手:选手ABCDE,10个评委分别对每一名选手打分,去除最高分,去除评委中最低分,取平均分。 #### 3.4.2 实现步骤 1. 创建五名选手,放到vector中 2. 遍历vector容器,取出来每一个选手,执行for循环,可以把10个评分打分存到deque容器中 3. sort算法对deque容器中分数排序,去除最高和最低分 4. deque容器遍历一遍,累加总分 5. 获取平均分 **示例代码:** ```C++ //选手类 class Person { public: Person(string name, int score) { this->m_Name = name; this->m_Score = score; } string m_Name; //姓名 int m_Score; //平均分 }; void createPerson(vector<Person>&v) { string nameSeed = "ABCDE"; for (int i = 0; i <5; i++) { string name = "选手"; name += nameSeed[i]; int score = 0; Person p(name, score); //将创建的person对象 放入到容器中 v.push_back(p); } } //打分 void setScore(vector<Person>&v) { for (vector<Person>::iterator it = v.begin(); it != v.end(); it++) { //将评委的分数 放入到deque容器中 deque<int>? for (int i = 0; i <10; i++) { int score = rand() % 41 + 60; // 60 ~ 100 d.push_back(score); } //cout <<"选手: " < 13_44_32_65600 #### 3.6.2 queue 常用接口 功能描述:栈容器常用的对外接口 构造函数: - `queue<T>que;` //queue采用模板类实现,queue对象的默认构造形式 - `queue(const queue &que);` //拷贝构造函数 赋值操作: - `queue& operator=(const queue &que);` //重载等号操作符 数据存取: - `push(elem);` //往队尾添加元素 - `pop();` //从队头移除第一个元素 - `back();` //返回最后一个元素 - `front(); ` //返回第一个元素 大小操作: - `empty();` //判断堆栈是否为空 - `size(); ` //返回栈的大小 **示例:** ```C++ #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("唐僧", 30); Person p2("孙悟空", 1000); Person p3("猪八戒", 900); Person p4("沙僧", 800); //向队列中添加元素 入队操作 q.push(p1); q.push(p2); q.push(p3); q.push(p4); //队列不提供迭代器,更不支持随机访问 while (!q.empty()) { //输出队头元素 cout <<"队头元素-- 姓名: " <lst;` //list采用采用模板类实现,对象的默认构造形式: * `list(beg,end);` //构造函数将[beg, end)区间中的元素拷贝给本身。 * `list(n,elem);` //构造函数将n个elem拷贝给本身。 * `list(const list &lst);` //拷贝构造函数。 **示例:** ```C++ #include <list> void printList(const list<int>& L) { for (list<int>::const_iterator it = L.begin(); it != L.end(); it++) { cout <<*it <<" "; } cout <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); printList(L); //尾删 L.pop_back(); printList(L); //头删 L.pop_front(); printList(L); //插入 list<int>::iterator it = L.begin(); L.insert(++it, 1000); printList(L); //删除 it = L.begin(); L.erase(++it); printList(L); //移除 L.push_back(10000); L.push_back(10000); L.push_back(10000); printList(L); L.remove(10000); printList(L); //清空 L.clear(); printList(L); } int main() { test01(); system("pause"); return 0; } ``` 总结: * 尾插 --- push_back * 尾删 --- pop_back * 头插 --- push_front * 头删 --- pop_front * 插入 --- insert * 删除 --- erase * 移除 --- remove * 清空 --- clear #### 3.7.6 list 数据存取 **功能描述:** * 对list容器中数据进行存取 **函数原型:** * `front();` //返回第一个元素。 * `back();` //返回最后一个元素。 **示例:** ```C++ #include <list> //数据存取 void test01() { list<int>L1; L1.push_back(10); L1.push_back(20); L1.push_back(30); L1.push_back(40); //cout <val2; } //反转和排序 void test01() { list<int>L; L.push_back(90); L.push_back(30); L.push_back(20); L.push_back(70); printList(L); //反转容器的元素 L.reverse(); printList(L); //排序 L.sort(); //默认的排序规则 从小到大 printList(L); L.sort(myCompare); //指定规则,从大到小 printList(L); } int main() { test01(); system("pause"); return 0; } ``` 总结: * 反转 --- reverse * 排序 --- sort (成员函数) #### 3.7.8 排序案例 案例描述:将Person自定义数据类型进行排序,Person中属性有姓名、年龄、身高 排序规则:按照年龄进行升序,如果年龄相同按照身高进行降序 **示例:** ```C++ #include <list> #include <string> class Person { public: Person(string name, int age , int height) { m_Name = name; m_Age = age; m_Height = height; } public: 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 L; Person p1("刘备", 35 , 175); Person p2("曹操", 45 , 180); Person p3("孙权", 40 , 170); Person p4("赵云", 25 , 190); Person p5("张飞", 35 , 160); Person p6("关羽", 35 , 200); L.push_back(p1); L.push_back(p2); L.push_back(p3); L.push_back(p4); L.push_back(p5); L.push_back(p6); for (list<Person>::iterator it = L.begin(); it != L.end(); it++) { cout <<"姓名: " <st;` //默认构造函数: * `set(const set &st);` //拷贝构造函数 赋值: * `set& operator=(const set &st);` //重载等号操作符 **示例:** ```C++ #include <set> void printSet(set<int>& s) { for (set<int>::iterator it = s.begin(); it != s.end(); it++) { cout <<*it <<" "; } cout <s1; s1.insert(10); s1.insert(30); s1.insert(20); s1.insert(40); printSet(s1); //拷贝构造 set<int>s2(s1); printSet(s2); //赋值 set<int>s3; s3 = s2; printSet(s3); } int main() { test01(); system("pause"); return 0; } ``` 总结: * set容器插入数据时用insert * set容器插入数据的数据会自动排序 #### 3.8.3 set大小和交换 **功能描述:** * 统计set容器大小以及交换set容器 **函数原型:** * `size();` //返回容器中元素的数目 * `empty();` //判断容器是否为空 * `swap(st);` //交换两个集合容器 **示例:** ```C++ #include <set> void printSet(set<int>& s) { for (set<int>::iterator it = s.begin(); it != s.end(); it++) { cout <<*it <<" "; } cout <s1; s1.insert(10); s1.insert(30); s1.insert(20); s1.insert(40); if (s1.empty()) { cout <<"s1为空" <s1; s1.insert(10); s1.insert(30); s1.insert(20); s1.insert(40); set<int>s2; s2.insert(100); s2.insert(300); s2.insert(200); s2.insert(400); cout <<"交换前" <& s) { for (set<int>::iterator it = s.begin(); it != s.end(); it++) { cout <<*it <<" "; } cout <s1; //插入 s1.insert(10); s1.insert(30); s1.insert(20); s1.insert(40); printSet(s1); //删除 s1.erase(s1.begin()); printSet(s1); s1.erase(30); printSet(s1); //清空 //s1.erase(s1.begin(), s1.end()); s1.clear(); printSet(s1); } int main() { test01(); system("pause"); return 0; } ``` 总结: * 插入 --- insert * 删除 --- erase * 清空 --- clear #### 3.8.5 set查找和统计 **功能描述:** * 对set容器进行查找数据以及统计数据 **函数原型:** * `find(key);` //查找key是否存在,若存在,返回该键的元素的迭代器;若不存在,返回set.end(); * `count(key);` //统计key的元素个数 **示例:** ```C++ #include <set> //查找和统计 void test01() { set<int>s1; //插入 s1.insert(10); s1.insert(30); s1.insert(20); s1.insert(40); //查找 set<int>::iterator pos = s1.find(30); if (pos != s1.end()) { cout <<"找到了元素 : " <<*pos <s; pair<set<int>::iterator, bool> ret = s.insert(10); if (ret.second) { cout <<"第一次插入成功!" <ms; ms.insert(10); ms.insert(10); for (multiset<int>::iterator it = ms.begin(); it != ms.end(); it++) { cout <<*it <<" "; } cout <p ( value1, value2 );` * `pair<type, type>p = make_pair( value1, value2 );` **示例:** ```C++ #include <string> //对组创建 void test01() { pair<string, int>p(string("Tom"), 20); cout <<"姓名: " << p.first <<" 年龄: " <p2 = make_pair("Jerry", 10); cout <<"姓名: " <v2; } }; void test01() { set<int>s1; s1.insert(10); s1.insert(40); s1.insert(20); s1.insert(30); s1.insert(50); //默认从小到大 for (set<int>::iterator it = s1.begin(); it != s1.end(); it++) { cout <<*it <<" "; } cout <s2; s2.insert(10); s2.insert(40); s2.insert(20); s2.insert(30); s2.insert(50); for (set<int, MyCompare>::iterator it = s2.begin(); it != s2.end(); it++) { cout <<*it <<" "; } cout <p2.m_Age; } }; void test01() { set<Person, comparePerson>s; Person p1("刘备", 23); Person p2("关羽", 27); Person p3("张飞", 25); Person p4("赵云", 21); s.insert(p1); s.insert(p2); s.insert(p3); s.insert(p4); for (set<Person, comparePerson>::iterator it = s.begin(); it != s.end(); it++) { cout <<"姓名: " <mp;` //map默认构造函数: * `map(const map &mp);` //拷贝构造函数 **赋值:** * `map& operator=(const map &mp);` //重载等号操作符 **示例:** ```C++ #include <map> void printMap(map<int,int>&m) { for (map<int, int>::iterator it = m.begin(); it != m.end(); it++) { cout <<"key = " <v2; } }; void test01() { //默认从小到大排序 //利用仿函数实现从大到小排序 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)); for (map<int, int, MyCompare>::iterator it = m.begin(); it != m.end(); it++) { cout <<"key:" <5; } }; void test01() { vector<int>v; for (int i = 0; i <10; i++) { v.push_back(i); } vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive()); if (it == v.end()) { cout <<"没找到!" <num2; } }; 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()); for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout <<*it <<" "; } cout <T plus<T>` //加法仿函数 * `template<class T>T minus<T>` //减法仿函数 * `template<class T>T multiplies<T>` //乘法仿函数 * `template<class T>T divides<T>` //除法仿函数 * `template<class T>T modulus<T>` //取模仿函数 * `template<class T>T negate<T>` //取反仿函数 **示例:** ```C++ #include <functional> //negate void test01() { negate<int>n; cout <p; cout <bool equal_to<T>` //等于 * `template<class T>bool not_equal_to<T>` //不等于 * `template<class T>bool greater<T>` //大于 * `template<class T>bool greater_equal<T>` //大于等于 * `template<class T>bool less<T>` //小于 * `template<class T>bool less_equal<T>` //小于等于 **示例:** ```C++ #include <functional> #include <vector> #include <algorithm> class MyCompare { public: bool operator()(int v1,int v2) { return v1 >v2; } }; void test01() { vector<int>v; v.push_back(10); v.push_back(30); v.push_back(50); v.push_back(40); v.push_back(20); for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout <<*it <<" "; } cout <bool logical_and<T>` //逻辑与 * `template<class T>bool logical_or<T>` //逻辑或 * `template<class T>bool logical_not<T>` //逻辑非 **示例:** ```C++ #include <vector> #include <functional> #include <algorithm> void test01() { vector<bool>v; v.push_back(true); v.push_back(false); v.push_back(true); v.push_back(false); for (vector<bool>::iterator it = v.begin();it!= v.end();it++) { cout <<*it <<" "; } cout <v2; v2.resize(v.size()); transform(v.begin(), v.end(), v2.begin(), logical_not<bool>()); for (vector<bool>::iterator it = v2.begin(); it != v2.end(); it++) { cout <<*it <<" "; } cout <v; for (int i = 0; i <10; i++) { v.push_back(i); } //遍历算法 for_each(v.begin(), v.end(), print01); cout <v; for (int i = 0; i <10; i++) { v.push_back(i + 1); } //查找容器中是否有 5 这个元素 vector<int>::iterator it = find(v.begin(), v.end(), 5); if (it == v.end()) { cout <<"没有找到!" <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); vector<Person>::iterator it = find(v.begin(), v.end(), p2); if (it == v.end()) { cout <<"没有找到!" <5; } }; void test01() { vector<int>v; for (int i = 0; i <10; i++) { v.push_back(i + 1); } vector<int>::iterator it = find_if(v.begin(), v.end(), GreaterFive()); if (it == v.end()) { cout <<"没有找到!" <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); vector<Person>::iterator it = find_if(v.begin(), v.end(), Greater20()); if (it == v.end()) { cout <<"没有找到!" <v; v.push_back(1); v.push_back(2); v.push_back(5); v.push_back(2); v.push_back(4); v.push_back(4); v.push_back(3); //查找相邻重复元素 vector<int>::iterator it = adjacent_find(v.begin(), v.end()); if (it == v.end()) { cout <<"找不到!" <v; v.push_back(1); v.push_back(2); v.push_back(4); v.push_back(5); v.push_back(3); v.push_back(4); v.push_back(4); int num = count(v.begin(), v.end(), 4); cout <<"4的个数为: " <v; Person p1("刘备", 35); Person p2("关羽", 35); Person p3("张飞", 35); Person p4("赵云", 30); Person p5("曹操", 25); v.push_back(p1); v.push_back(p2); v.push_back(p3); v.push_back(p4); v.push_back(p5); Person p("诸葛亮",35); int num = count(v.begin(), v.end(), p); cout <<"num = " <v; v.push_back(1); v.push_back(2); v.push_back(4); v.push_back(5); v.push_back(3); v.push_back(4); v.push_back(4); int num = count_if(v.begin(), v.end(), Greater4()); cout <<"大于4的个数为: " <v; Person p1("刘备", 35); Person p2("关羽", 35); Person p3("张飞", 35); Person p4("赵云", 30); Person p5("曹操", 25); v.push_back(p1); v.push_back(p2); v.push_back(p3); v.push_back(p4); v.push_back(p5); int num = count_if(v.begin(), v.end(), AgeLess35()); cout <<"小于35岁的个数:" <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 <v; for(int i = 0 ; i <10;i++) { v.push_back(i); } for_each(v.begin(), v.end(), myPrint()); cout <v1; vector<int>v2; 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()); //合并 需要两个有序序列 merge(v1.begin(), v1.end(), v2.begin(), v2.end(), vtarget.begin()); for_each(vtarget.begin(), vtarget.end(), myPrint()); cout <v; v.push_back(10); v.push_back(30); v.push_back(50); v.push_back(20); v.push_back(40); cout <<"反转前: " <v1; for (int i = 0; i <10; i++) { v1.push_back(i + 1); } vector<int>v2; v2.resize(v1.size()); copy(v1.begin(), v1.end(), v2.begin()); for_each(v2.begin(), v2.end(), myPrint()); cout <v; v.push_back(20); v.push_back(30); v.push_back(20); v.push_back(40); v.push_back(50); v.push_back(10); v.push_back(20); cout <<"替换前:" <v; v.push_back(20); v.push_back(30); v.push_back(20); v.push_back(40); v.push_back(50); v.push_back(10); v.push_back(20); cout <<"替换前:" <v1; vector<int>v2; for (int i = 0; i <10; i++) { v1.push_back(i); v2.push_back(i+100); } cout <<"交换前: " <v; for (int i = 0; i <= 100; i++) { v.push_back(i); } int total = accumulate(v.begin(), v.end(), 0); cout <<"total = " <v; v.resize(10); //填充 fill(v.begin(), v.end(), 100); for_each(v.begin(), v.end(), myPrint()); cout <v1; vector<int>v2; for (int i = 0; i <10; i++) { v1.push_back(i); v2.push_back(i+5); } vector<int>vTarget; //取两个里面较小的值给目标容器开辟空间 vTarget.resize(min(v1.size(), v2.size())); //返回目标容器的最后一个元素的迭代器地址 vector<int>::iterator itEnd = set_intersection(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin()); for_each(vTarget.begin(), itEnd, myPrint()); cout <v1; vector<int>v2; for (int i = 0; i <10; i++) { v1.push_back(i); v2.push_back(i+5); } vector<int>vTarget; //取两个容器的和给目标容器开辟空间 vTarget.resize(v1.size() + v2.size()); //返回目标容器的最后一个元素的迭代器地址 vector<int>::iterator itEnd = set_union(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin()); for_each(vTarget.begin(), itEnd, myPrint()); cout <v1; vector<int>v2; for (int i = 0; i <10; i++) { v1.push_back(i); v2.push_back(i+5); } vector<int>vTarget; //取两个里面较大的值给目标容器开辟空间 vTarget.resize( max(v1.size() , v2.size())); //返回目标容器的最后一个元素的迭代器地址 cout <<"v1与v2的差集为: " < 最后于 2023-3-12 被大理寺少卿编辑 ,原因:

最新回复 ( 1 )
全部楼主