C++ 【第三篇】泛型编程之STL(一)
STL
一模板
函数模板
//交换整型函数 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 = " << a << endl; cout << "b = " << b << endl; } int main() { test01(); system("pause"); return 0; }
//利用模板提供通用的交换函数 template<class T> void mySwap(T& a, T& b) { T temp = a; a = b; b = temp; } // 1、自动类型推导,必须推导出一致的数据类型T,才可以使用 void test01() { int a = 10; int b = 20; char c = 'c'; mySwap(a, b); // 正确,可以推导出一致的T //mySwap(a, c); // 错误,推导不出一致的T类型 } // 2、模板必须要确定出T的数据类型,才可以使用 template<class T> void func() { cout << "func 调用" << endl; } void test02() { //func(); //错误,模板不能独立使用,必须确定出T的类型 func<int>(); //利用显示指定类型的方式,给T一个类型,才可以使用该模板 } int main() { test01(); test02(); system("pause"); return 0; }
案例描述: * 利用函数模板封装一个排序的函数,可以对**不同数据类型数组**进行排序 * 排序规则从大到小,排序算法为**选择排序** * 分别利用**char数组**和**int数组**进行测试 //交换的函数模板 template<typename T> void mySwap(T &a, T&b) { T temp = a; a = b; b = temp; } template<class T> // 也可以替换成typename //利用选择排序,进行对数组从大到小的排序 void mySort(T arr[], int len) { for (int i = 0; i < len; i++) { int max = i; //最大数的下标 for (int j = i + 1; j < len; j++) { if (arr[max] < arr[j]) { max = j; } } if (max != i) //如果最大数的下标不是i,交换两者 { mySwap(arr[max], arr[i]); } } } template<typename T> void printArray(T arr[], int len) { for (int i = 0; i < len; i++) { cout << arr[i] << " "; } cout << endl; } void test01() { //测试char数组 char charArr[] = "bdcfeagh"; int num = sizeof(charArr) / sizeof(char); mySort(charArr, num); printArray(charArr, num); } void test02() { //测试int数组 int intArr[] = { 7, 5, 8, 1, 3, 9, 2, 4, 6 }; int num = sizeof(intArr) / sizeof(int); mySort(intArr, num); printArray(intArr, num); } int main() { test01(); test02(); system("pause"); return 0; }
//普通函数 int myAdd01(int a, int b) { return a + b; } //函数模板 template<class T> T myAdd02(T a, T b) { return a + b; } //使用函数模板时,如果用自动类型推导,不会发生自动类型转换,即隐式类型转换 void test01() { int a = 10; int b = 20; char c = 'c'; cout << myAdd01(a, c) << endl; //正确,将char类型的'c'隐式转换为int类型 'c' 对应 ASCII码 99 //myAdd02(a, c); // 报错,使用自动类型推导时,不会发生隐式类型转换 myAdd02<int>(a, c); //正确,如果用显示指定类型,可以发生隐式类型转换 } int main() { test01(); system("pause"); return 0; }
类模板
#include <string> //类模板 template<class NameType, class AgeType> class Person { public: Person(NameType name, AgeType age) { this->mName = name; this->mAge = age; } void showPerson() { cout << "name: " << this->mName << " age: " << this->mAge << endl; } public: NameType mName; AgeType mAge; }; void test01() { // 指定NameType 为string类型,AgeType 为 int类型 Person<string, int>P1("孙悟空", 999); P1.showPerson(); } int main() { test01(); system("pause"); return 0; }
//总结: * 类模板使用只能用显示指定类型方式 * 类模板中的模板参数列表可以有默认参数 #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: " << this->mName << " age: " << this->mAge << endl; } public: NameType mName; AgeType mAge; }; //1、类模板没有自动类型推导的使用方式 void test01() { // Person p("孙悟空", 1000); // 错误 类模板使用时候,不可以用自动类型推导 Person <string ,int>p("孙悟空", 1000); //必须使用显示指定类型的方式,使用类模板 p.showPerson(); } //2、类模板在模板参数列表中可以有默认参数 void test02() { Person <string> p("猪八戒", 999); //类模板中的模板参数列表 可以指定默认参数 p.showPerson(); } int main() { test01(); test02(); system("pause"); return 0; }
class Person1 { public: void showPerson1() { cout << "Person1 show" << endl; } }; class Person2 { public: void showPerson2() { cout << "Person2 show" << endl; } }; template<class T> class MyClass { public: T obj; //类模板中的成员函数,并不是一开始就创建的,而是在模板调用时再生成 void fun1() { obj.showPerson1(); } void fun2() { obj.showPerson2(); } }; void test01() { MyClass<Person1> m; m.fun1(); //m.fun2();//编译会出错,说明函数调用才会去创建成员函数 } int main() { test01(); system("pause"); return 0; }
#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 << "姓名: " << this->m_Name << " 年龄:" << this->m_Age << endl; } void test01() { Person<string, int> p("Tom", 20); p.showPerson(); } int main() { test01(); system("pause"); return 0; }
类模板分文件编写
问题:
- 
类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到
 
解决:
#pragma once #include <iostream> using namespace std; #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 << "姓名: " << this->m_Name << " 年龄:" << this->m_Age << endl; }
#include<iostream> using namespace std; //#include "person.h" #include "person.cpp" //解决方式1,包含cpp源文件 //解决方式2,将声明和实现写到一起,文件后缀名改为.hpp #include "person.hpp" void test01() { Person<string, int> p("Tom", 10); p.showPerson(); } int main() { test01(); system("pause"); return 0; }
...
二 STL
- 
 - 
STL 从广义上分为:
 
1 Vector
理解为数组
#include <vector> #include <algorithm> void MyPrint(int val) { cout << val << endl; } void test01() { //创建vector容器对象,并且通过模板参数指定容器中存放的数据的类型 vector<int> 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 << endl; pBegin++; } //第二种遍历方式: for (vector<int>::iterator it = v.begin(); it != v.end(); it++) { cout << *it << endl; } cout << endl; //第三种遍历方式: //使用STL提供标准遍历算法 头文件 algorithm for_each(v.begin(), v.end(), MyPrint); } int main() { test01(); system("pause"); return 0; }
#include <vector> #include <string> //自定义数据类型 class Person { public: Person(string name, int age) { mName = name; mAge = age; } public: string mName; int mAge; }; //存放对象 void test01() { vector<Person> 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 << endl; } } //放对象指针 void test02() { vector<Person*> 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:" << p->mName << " Age:" << (*it)->mAge << endl; } } int main() { test01(); test02(); system("pause"); return 0; }
#include <vector> //容器嵌套容器 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); } //将容器元素插入到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 << endl; } } int main() { test01(); system("pause"); return 0; }
#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为空" << endl; } else { cout << "v1不为空" << endl; cout << "v1的容量 = " << v1.capacity() << endl; cout << "v1的大小 = " << v1.size() << endl; } //resize 重新指定大小 ,若指定的更大,默认用0填充新位置,可以利用重载版本替换默认填充 v1.resize(15,10); printVector(v1); //resize 重新指定大小 ,若指定的更小,超出部分元素被删除 v1.resize(5); printVector(v1); } int main() { test01(); system("pause"); return 0; }
#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); //插入 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; }
#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; for (int i = 0; i < v1.size(); i++) { cout << v1.at(i) << " "; } cout << endl; cout << "v1的第一个元素为: " << v1.front() << endl; cout << "v1的最后一个元素为: " << v1.back() << endl; } int main() { test01(); system("pause"); return 0; }
#include <vector> void test01() { vector<int> 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:" << num << endl; } int main() { test01(); system("pause"); return 0; }
2string容器
#include <string> //string构造 void test01() { string s1; //创建空字符串,调用无参构造函数 cout << "str1 = " << s1 << endl; const char* str = "hello world"; string s2(str); //把c_string转换成了string cout << "str2 = " << s2 << endl; string s3(s2); //调用拷贝构造函数 cout << "str3 = " << s3 << endl; string s4(10, 'a'); cout << "str3 = " << s3 << endl; } int main() { test01(); system("pause"); return 0; }
//赋值 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; str5.assign("hello c++",5); cout << "str5 = " << str5 << endl; string str6; str6.assign(str5); cout << "str6 = " << str6 << endl; string str7; str7.assign(5, 'x'); cout << "str7 = " << str7 << endl; } int main() { test01(); system("pause"); return 0; }
//字符串拼接 void test01() { string str1 = "我"; str1 += "爱玩游戏"; cout << "str1 = " << str1 << endl; str1 += ':'; cout << "str1 = " << str1 << endl; string str2 = "LOL DNF"; str1 += str2; cout << "str1 = " << str1 << endl; string str3 = "I"; str3.append(" love "); str3.append("game abcde", 4); //str3.append(str2); str3.append(str2, 4, 3); // 从下标4位置开始 ,截取3个字符,拼接到字符串末尾 cout << "str3 = " << str3 << endl; } int main() { test01(); system("pause"); return 0; }
//查找和替换 void test01() { //查找 string str1 = "abcdefgde"; int pos = str1.find("de"); if (pos == -1) { cout << "未找到" << endl; } else { cout << "pos = " << pos << endl; } pos = str1.rfind("de"); cout << "pos = " << pos << endl; } void test02() { //替换 string str1 = "abcdefgde"; str1.replace(1, 3, "1111"); cout << "str1 = " << str1 << endl; } int main() { //test01(); //test02(); system("pause"); return 0; }
//字符串比较 void test01() { string s1 = "hello"; string s2 = "aello"; int ret = s1.compare(s2); if (ret == 0) { cout << "s1 等于 s2" << endl; } else if (ret > 0) { cout << "s1 大于 s2" << endl; } else { cout << "s1 小于 s2" << endl; } } int main() { test01(); system("pause"); return 0; }
//string字符串中单个字符存取有两种方式,利用 [ ] 或 at void test01() { string str = "hello world"; for (int i = 0; i < str.size(); i++) { cout << str[i] << " "; } cout << endl; for (int i = 0; i < str.size(); i++) { cout << str.at(i) << " "; } cout << endl; //字符修改 str[0] = 'x'; str.at(1) = 'x'; cout << str << endl; } int main() { test01(); system("pause"); return 0; }
//字符串插入和删除 void test01() { string str = "hello"; str.insert(1, "111"); cout << str << endl; str.erase(1, 3); //从1号位置开始3个字符 cout << str << endl; } int main() { test01(); system("pause"); return 0; }
//子串 void test01() { string str = "abcdefg"; string subStr = str.substr(1, 3); cout << "subStr = " << subStr << endl; string email = "hello@sina.com"; int pos = email.find("@"); string username = email.substr(0, pos); cout << "username: " << username << endl; } int main() { test01(); system("pause"); return 0; }
3
功能:将数据进行链式存储
链表(list)是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接实现的
....
5
...
6
- 
 - 
pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)
 - 
 
map和multimap区别:
- 
map不允许容器中有重复key值元素
 - 
multimap允许容器中有重复key值元素
 
#include <map> void printMap(map<int,int>&m) { for (map<int, int>::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)); m.insert(pair<int, int>(2, 20)); m.insert(pair<int, int>(3, 30)); printMap(m); map<int, int>m2(m); //拷贝构造 printMap(m2); map<int, int>m3; m3 = m2; //赋值 printMap(m3); } int main() { test01(); system("pause"); return 0; }
#include <map> void printMap(map<int,int>&m) { for (map<int, int>::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)); m.insert(pair<int, int>(2, 20)); m.insert(pair<int, int>(3, 30)); if (m.empty()) { cout << "m为空" << endl; } else { cout << "m不为空" << endl; cout << "m的大小为: " << m.size() << endl; } } //交换 void test02() { 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)); map<int, int>m2; m2.insert(pair<int, int>(4, 100)); m2.insert(pair<int, int>(5, 200)); m2.insert(pair<int, int>(6, 300)); cout << "交换前" << endl; printMap(m); printMap(m2); cout << "交换后" << endl; m.swap(m2); printMap(m); printMap(m2); } int main() { test01(); test02(); system("pause"); return 0; }
#include <map> void printMap(map<int,int>&m) { for (map<int, int>::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)); //第二种插入方式 m.insert(make_pair(2, 20)); //第三种插入方式 m.insert(map<int, int>::value_type(3, 30)); //第四种插入方式 m[4] = 40; printMap(m); //删除 m.erase(m.begin()); printMap(m); m.erase(3); printMap(m); //清空 m.erase(m.begin(),m.end()); m.clear(); printMap(m); } int main() { test01(); system("pause"); return 0; }
#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)); //查找 map<int, int>::iterator pos = m.find(3); if (pos != m.end()) { cout << "找到了元素 key = " << (*pos).first << " value = " << (*pos).second << endl; } else { cout << "未找到元素" << endl; } //统计 int num = m.count(3); cout << "num = " << num << endl; } int main() { test01(); system("pause"); return 0; }
#include <map> class MyCompare { public: bool operator()(int v1, int v2) { return v1 > 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:" << it->first << " value:" << it->second << endl; } } int main() { test01(); system("pause"); return 0; }
案例
- 
创建10名员工,放到vector中
 - 
 - 
分组后,将员工部门编号作为key,具体员工作为value,放入到multimap容器中
 - 
分部门显示员工信息
 
#include<iostream> using namespace std; #include <vector> #include <string> #include <map> #include <ctime> /* - 公司今天招聘了10个员工(ABCDEFGHIJ),10名员工进入公司之后,需要指派员工在那个部门工作 - 员工信息有: 姓名 工资组成;部门分为:策划、美术、研发 - 随机给10名员工分配部门和工资 - 通过multimap进行信息的插入 key(部门编号) value(员工) - 分部门显示员工信息 */ #define CEHUA 0 #define MEISHU 1 #define YANFA 2 class Worker { public: string m_Name; int m_Salary; }; void createWorker(vector<Worker>&v) { string nameSeed = "ABCDEFGHIJ"; for (int i = 0; i < 10; i++) { Worker worker; worker.m_Name = "员工"; worker.m_Name += nameSeed[i]; worker.m_Salary = rand() % 10000 + 10000; // 10000 ~ 19999 //将员工放入到容器中 v.push_back(worker); } } //员工分组 void setGroup(vector<Worker>&v,multimap<int,Worker>&m) { for (vector<Worker>::iterator it = v.begin(); it != v.end(); it++) { //产生随机部门编号 int deptId = rand() % 3; // 0 1 2 //将员工插入到分组中 //key部门编号,value具体员工 m.insert(make_pair(deptId, *it)); } } void showWorkerByGourp(multimap<int,Worker>&m) { // 0 A B C 1 D E 2 F G ... cout << "策划部门:" << endl; multimap<int,Worker>::iterator pos = m.find(CEHUA); int count = m.count(CEHUA); // 统计具体人数 int index = 0; for (; pos != m.end() && index < count; pos++ , index++) { cout << "姓名: " << pos->second.m_Name << " 工资: " << pos->second.m_Salary << endl; } cout << "----------------------" << endl; cout << "美术部门: " << endl; pos = m.find(MEISHU); count = m.count(MEISHU); // 统计具体人数 index = 0; for (; pos != m.end() && index < count; pos++, index++) { cout << "姓名: " << pos->second.m_Name << " 工资: " << pos->second.m_Salary << endl; } cout << "----------------------" << endl; cout << "研发部门: " << endl; pos = m.find(YANFA); count = m.count(YANFA); // 统计具体人数 index = 0; for (; pos != m.end() && index < count; pos++, index++) { cout << "姓名: " << pos->second.m_Name << " 工资: " << pos->second.m_Salary << endl; } } int main() { srand((unsigned int)time(NULL)); //1、创建员工 vector<Worker>vWorker; createWorker(vWorker); //2、员工分组 multimap<int, Worker>mWorker; setGroup(vWorker, mWorker); //3、分组显示员工 showWorkerByGourp(mWorker); ////测试 //for (vector<Worker>::iterator it = vWorker.begin(); it != vWorker.end(); it++) //{ // cout << "姓名: " << it->m_Name << " 工资: " << it->m_Salary << endl; //} system("pause"); return 0; }
总结:当数据以键值对形式存在,可以考虑用map 或 multimap
其他待 完成
    作者:华王
博客:https://www.cnblogs.com/huahuawang/
                    
                
                
            
        
浙公网安备 33010602011771号