相关视频——黑马程序员匠心之作|C++教程从0到1入门编程,学习编程不再难 -(167-263)
基础部分(1-83)—— 如果你准备学习C++,并且有C语言的基础,我希望你能简单的过一遍知识点。
核心部分(84-146)—— C++核心编程部分
案例1(147-166)——职工管理系统—— C++实现职工管理系统
C++提高编程 本阶段主要针对C++泛型编程和STL技术做详细讲解,探讨C++更深层次的使用
模板 模板的概念 模板就会通用的模具,大大提高复用性。
例如生活中的一寸照片、PPT模板。
模板的特点 :
模板不可以直接使用,它只是一个框架
模板的通用并不是万能的
函数模板
C++另一种编程思想称为泛型编程 ,主要利用的技术就是模板
C++提供两种模板机制,函数模板 和类模板 。
函数模板语法 函数模板作用: 建立一个通用的函数,其函数返回值类型和形参类型可以不具体制定,用一个虚拟的类型 来代表。
语法 :
1 2 template <typename T>函数声明或定义
解释 : template——声明创建模板
typena me——表明其后面的 符号为一种数据类型,可以用class代替。
T——通用的数据类型,名称可以替换,通常为大写字母。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include <iostream> using namespace std ;void SwapInt (int &a, int &b) { int temp = b; b = a; a = 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 ; MySwap(a, b); cout << a << endl ; cout << b << endl ; double c = 11.1 ; double d = 12.2 ; MySwap<double >(c, d); cout << c << endl ; cout << d << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
函数模板利用关键字template
使用函数类型模板有两种方式:自动类型推导、显示指定类型
模板的目的是为了提高复用性,将类型参数化
函数模板注意事项 注意事项 :
自动类型推导,必须推导出一致的数据类型T才能使用
模板必须要确定出T的数据类型,才可以使用
函数模板案例 案例描述 :
利用函数模板封装一个排序的函数,可以对不用数据类型数组进行排序
排序规则从大到小,排序算法为选择排序
分别利用char数组和int数组进行测试
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 #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 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) { mySwap(arr[max], arr[i]); } } } template <class T >void myPrint (T arr[], int len) { for (int i = 0 ; i < len; i++) { cout << arr[i]<< endl ; } } void test01 () { char charArr[] = "badcfe" ; int num = sizeof (charArr) / sizeof (char ); mySort(charArr, num); myPrint(charArr, num); } void test02 () { int intArr[] = {2 ,3 ,78 ,9 ,7 }; int num = sizeof (intArr) / sizeof (int ); mySort(intArr, num); myPrint(intArr, num); } int main (void ) { test01(); test02(); return 0 ; }
普通函数与函数模板的区别 普通函数与函数模板的区别 :
普通函数调用时可以发生自动类型转换(隐式类型推导)
函数模板调用时,如果利用自动类型推导,不会发生隐式类型转换
如果利用显式指定类型的方式,可以发生隐式类型转换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #include <iostream> using namespace std ;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 ; cout << myAdd02<int >(a, c) << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :建议使用显式指定类型的方式,调用函数模板,因为可以自己确定通用类型T
普通函数与函数模板的调用规则 调用规则如下:
如果函数模板和普通函数都可以实现,优先调用普通函数
可以通过空模板参数列表来强制调用函数模板
函数模板也可以发生重载
如果函数模板可以产生更好的匹配,优先调用函数模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <iostream> using namespace std ;void myPrint (int a, int b) { cout << "调用普通函数" << endl ; } template <class T >void myPrint (T a, T b) { cout << "调用模板" << endl ; } template <class T >void myPrint (T a, T b,T c) { cout << "调用重载模板" << endl ; } void test01 () { int a = 10 ; int b = 20 ; myPrint(a, b); myPrint<>(a,b); myPrint(a, b, 100 ); char c1 = 'a' ; char c2 = 'b' ; myPrint(c1, c2); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :既然提供了函数模板,最好就不要提供普通函数,否则容易出现二义性。
模板的局限性 局限性 :
模板的通用性并不是万能的。
1 2 3 4 5 template <class T >void f (T a,T b) { a = b; }
在上述代码中提供的赋值操作,如果传入的a和b是一个数组,就无法实现了。
再例如 :
1 2 3 4 5 6 template <class T >void f (T a,T b) { if (a>b) {......} }
在上述代码中,如果T的数据类型传入的是像Person这样的自定义类型,也无法正常运行。
因此C++为了解决这种问题,提供模板的重载,可以为这些特定的类型 提供具体化 的模板。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 #include <iostream> #include <string> using namespace std ;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 <>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 << "相等" << endl ; } else { cout << "不相等" << endl ; } } void test02 () { Person p1 ("Tom" , 10 ) ; Person p2 ("Tom" , 10 ) ; bool ret = myCompare(p1, p2); if (ret) { cout << "相等" << endl ; } else { cout << "不相等" << endl ; } } int main (void ) { test01(); test02(); system("pause" ); return 0 ; }
总结 :
利用具体化的模板,可以解决自定义类型的通用化
学习模板并不是为了写模板,而是在STL能够运用系统系统的模板
(知道模板怎么写,并且会有别人写好的模板就可以了。)
类模板 类模板语法 类模板作用:
建立一个通用类, 类中成员数据可以不具体指定,用一个虚拟的类型来代表
语法:
解释 :
template< typename T>——声明创建模板
typename——表明其后面的符号是一种数据类型,可以用class代替
T——通用的数据类型,名称可以替换,通常为大写字母
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <iostream> #include <string> using namespace std ;template <class NameType ,class AgeType >class Person { public : Person(NameType name, AgeType age) { this ->m_Age = age; this ->m_Name = name; } void showPerson () { cout << this ->m_Name << this ->m_Age << endl ; } NameType m_Name; AgeType m_Age; }; void test01 () { Person<string , int >p1("张三" ,10 ); p1.showPerson(); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
类模板和函数模板语法相似,在声明模板template后面加类,次类称为类模板。
类模板与函数模板的区别 类模板与函数模板的区别主要有两点:
类模板没有自动类型推导的使用方式
类模板在模板参数列表中可以有默认参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #include <iostream> #include <string> using namespace std ;template <class NameType , class AgeType = int >class Person { public : Person(NameType name,AgeType age) { this ->m_Name = name; this ->m_Age = age; } void ShowPerson () { cout << this ->m_Name << this ->m_Age << endl ; } NameType m_Name; AgeType m_Age; }; void test01 () { Person<string ,int >p("李四" , 13 ); p.ShowPerson(); } void test02 () { Person<string >p2("张三" , 13 ); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
类模板使用只能用显式指定类型方式
类模板中的模板参数列表可以有默认参数
类模板中的成员函数创建实际 类模板中成员函数和普通类中成员函数创建实际是有区别的:
普通类中的成员函数一开始就可以创建
类模板中的成员函数在调用时才创建
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 #include <iostream> #include <string> using namespace std ;class Person1 { public : void showPerson1 () { cout << "Person show1" << endl ; } }; class Person2 { public : void showPerson2 () { cout << "Person show2" << endl ; } }; template <class T >class MyClass { public : T obj; void func1 () { obj.showPerson1(); } void func2 () { obj.showPerson2(); } }; void test01 () { MyClass<Person2>m; m.func1(); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : 类模板中的成员函数并不是一开始就创建的,在调用时才去创建。
类模板对象做函数参数 学习目标:类模板实例化出的对象,向函数传参的方式
一共有三种传入方式
指定传入的类型——直接显式对象的数据类型
参数模板化——将对象中的参数变为模板参数进行传递
整个类模板化——将这个对象类型,模板化进行传递
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 #include <iostream> using namespace std ;template <class T1 ,class T2 >class Person { public : Person(T1 name,T2 age) { this ->m_Name = name; this ->m_Age = age; } void showPerson () { cout << this ->m_Name << this ->m_Age << endl ; } T1 m_Name; T2 m_Age; }; void PrintPerson1 (Person<string ,int >&p) { p.showPerson(); } void test01 () { Person<string , int >p1("张三" ,11 ); PrintPerson1(p1); } template <class T1 ,class T2 >void PrintPerson2 (Person<T1, T2>&p) { p.showPerson(); cout << "T1的数据类型为" << typeid (T1).name() << endl ; cout << "T2的数据类型为" << typeid (T2).name() << endl ; } void test02 () { Person<string , int >p2("李四" , 12 ); PrintPerson2(p2); } template <class T >void PrintPerson3 (T &p) { p.showPerson(); cout << "T的数据类型为" << typeid (T).name() << endl ; } void test03 () { Person<string , int >p3("赵四" , 14 ); PrintPerson3(p3); } int main (void ) { test01(); test02(); test03(); system("pause" ); return 0 ; }
总结 :
通过类模板创建的对象,可以有三种方式向函数中进行传参
使用比较广泛得是第一种,指定传入的类型
类模板与继承 当类模板碰到继承时,需要注意一下几点:
当子类继承的父类是一个类模板时,子类在声明的时候,要指定出父类中T的类型
如果不想指定,编译器无法给子类分配内存‘
如果想灵活指定出父类中T的类型,子类也需要变为类模板
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <iostream> using namespace std ;template <class T >class Base { T m; }; class Son :public Base<int >{ }; void test01 () { Son s1; } template <class T1 ,class T2 >class Son2 :public Base<T2>{ public : Son2() { cout << typeid (T1).name()<< endl ; cout << typeid (T2).name()<< endl ; } T1 obj; }; void test02 () { Son2<int , char >s2; } int main (void ) { test02(); system("pause" ); return 0 ; }
总结 : 如果父类是类模板,子类需要指定出父类中T的数据类型。
类模板成员函数类外实现 学习目标 :
能够掌握类模板中的成员函数类外实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <iostream> #include <string> using namespace std ;template <class T1 ,class T2 >class Person { public : Person(T1 name, T2 age); void showPerson () ; 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 >p1("新二" , 13 ); p1.showPerson(); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
类模板中成员函数类外实现时,需要加上模板参数列表。
类模板分文件编写 学习目标 :
掌握类模板成员函数分文件编写产生的问题以及解决方式
问题 :类模板中成员函数创建时机是在调用阶段,导致分文件编写时链接不到
解决 :
解决方式1:直接包含.cpp源文件
解决方式2:将声明.h和实现.cpp在到同一个文件中,并更改后缀名为.hpp,hpp是约定俗成的名称,并不是强制
.hpp文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #pragma once #include <iostream> using namespace std ;template <class T1 , class T2 >class Person { public : Person(T1 name, T2 age); void showPerson () ; 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 ; }
.cpp文件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 #include <iostream> #include "Person.hpp" using namespace std ;#include <string> void test01 () { Person<string , int >p1("伞兵" , 18 ); p1.showPerson(); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
主流的解决方式是第二种,将类模板成员函数写到一起,并将后缀名改为.hpp
类模板与友元 学习目标 : 掌握类模板配合友元函数的类内和类外实现
全局函数类内实现,直接在类内声明友元即可、
全局函数类外实现,需要提前让编译器知道全局函数的存在
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 #include <iostream> #include <string> using namespace std ;template <class T1 , class T2 >class Person ;template <class T1 , class T2 >void PrintPerosn2 (Person<T1, T2>p) { cout << "类外实现" << p.m_Name << p.m_Age < endl ; } template <class T1 ,class T2 >class Person { friend void PrintPerosn (Person<T1,T2>p) { cout << p.m_Name << p.m_Age << endl ; } friend void PrintPerosn2<>(Person<T1, T2>p); public : Person(T1 name,T2 age) { this ->m_Name = name; this ->m_Age = age; } private : T1 m_Name; T2 m_Age; }; void test01 () { Person<string , int >p("zbc" , 12 ); PrintPerosn(p); } void test02 () { Person<string , int >p2("年轻人" , 18 ); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
建议全局函数做类内实现,用法简单,而且编译器可以直接识别。
类模板案例 案例描述 :
可以对内置数据类型以及自定义数据类型的数据进行存储
将数组中的数据存储到堆区
构造函数中可以传入数组的容量
提供对应的拷贝构造函数以及operator=防止浅拷贝问题
提供尾插法和尾删法对数组中的数据进行增加和删除
可以通过下标的方式访问数组中的元素
可以获取数组汇中当前元素个数和数组的容量
MyArry.hpp中代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 #pragma once #include <iostream> using namespace std ;template <class T >class MyArry { public : MyArry(int capacity) { this ->m_Capacity = capacity; this ->m_Size = 0 ; this ->pAddress = new T[this ->m_Capacity]; } MyArry(const MyArry& arr) { this ->m_Capacity = arr.m_Capacity; this ->m_Size = arr.m_Size; this ->pAddress = new T[arr.m_Capacity]; for (int i = 0 ; i < this ->m_Size; i++) { this ->pAddress[i] = arr.pAddress[i]; } } MyArry& operator =(const MyArry& arr) { if (this ->pAddress != NULL ) { delete [] this ->pAddress; this ->pAddress = NULL ; this ->m_Capacity = 0 ; this ->m_Size = 0 ; } this ->m_Capacity = arr.m_Capacity; this ->m_Size = arr.m_Size; this ->pAddress = new T[arr.m_Capacity]; for (int i = 0 ; i < this ->m_Size; i++) { this ->pAddress[i] = arr.pAddress[i]; } return *this ; } void PushBack (const T& val) { if (this ->m_Capacity == this ->m_Size) { return ; } this ->pAddress[this ->m_Size] = val; this ->m_Size++; } void PopBack () { if (this ->m_Size == 0 ) { return ; } this ->m_Size--; } T& operator [](int index) { return this ->pAddress[index]; } int getCapacity () { return this ->m_Capacity; } int getSize () { return this ->m_Size; } ~MyArry() { if (this ->pAddress != NULL ) { delete [] this ->pAddress; this ->pAddress = NULL ; } } private : T* pAddress; int m_Capacity; int m_Size; };
test.cpp中代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 #include <iostream> #include "MyArray.hpp" #include <string> using namespace std ;void PrintArry (MyArry <int > &arr) { for (int i = 0 ; i < arr.getSize(); i++) { cout << arr[i] << endl ; } } void test01 () { MyArry <int >arr1(5 ); for (int i = 0 ; i < 5 ; i++) { arr1.PushBack(i); } cout << "arr1的打印输出" << endl ; PrintArry(arr1); cout << "arr1的容量为" << arr1.getCapacity() << endl ; cout << "arr1的大小为" << arr1.getSize() << endl ; cout << "arr2的打印输出" << endl ; MyArry <int >arr2(arr1); PrintArry(arr2); arr2.PopBack(); cout << "arr2尾删后" << endl ; cout << "arr2的容量为" << arr2.getCapacity() << endl ; cout << "arr2的大小为" << arr2.getSize() << endl ; } class Person { public : Person(){}; Person(string name,int age) { this ->m_Name = name; this ->m_Age = age; } string m_Name; int m_Age; }; void PrintPersonArry (MyArry<Person>& arr) { for (int i = 0 ; i < arr.getSize(); i++) { cout << "姓名" << arr[i].m_Name << "年龄" << arr[i].m_Age << endl ; } } void test02 () { MyArry<Person>arr(10 ); Person p1 ("伞兵1" , 21 ) ; Person p2 ("伞兵2" , 22 ) ; Person p3 ("伞兵3" , 23 ) ; Person p4 ("伞兵4" , 24 ) ; Person p5 ("伞兵5" , 25 ) ; arr.PushBack(p1); arr.PushBack(p2); arr.PushBack(p3); arr.PushBack(p4); arr.PushBack(p5); PrintPersonArry(arr); cout << "arr容量为" << arr.getCapacity() << endl ; cout << "arr大小为" << arr.getSize() << endl ; } int main (void ) { test01(); test02(); system("pause" ); return 0 ; }
总结 : 能够利用所学知识点实现通用的数组。
STL初识 STL的诞生
长久以来,软件届就一直希望建立一种可重复利用的东西
C++的面向对象和泛型编程思想,目的就是复用性的提升
大多情况下,数据结构和算法都未能有一套标准,导致被迫从事大量重复工作
为了建立数据结构和算法的一套标准,诞生了STL
STL基本概念
STL(Standard Template Library,标准模板库)
STL从广义上分为:容器(container)算法(algorithm)迭代器(iterator)
容器和算法之间通过迭代器进行无缝连接
STL几乎所有的代码都采用了模板类或者模板函数
STL六大组建 STL大体分为六大组件,分别是:容器、算法、迭代器、仿函数、适配器(配接器)、空间配置器。
容器:各种数据结构,如vector、list、deque、set、map等,用来存放数据。
算法:常用的各种算法,如sort、find、copy、for_each等
迭代器:扮演了容器与算法之间的胶合剂
仿函数:行为类似函数,可作为算法的某种策略
适配器:一种用来修饰容器或者仿函数或迭代器结构的东西。
空间配置器:负责空间的配置与管理。
STL中容器、算法、迭代器 容器 :置物之所也
STL容器就是将运用最广泛的一些数据结构实现出来
常用的数据结构:数组、链表、树、栈、队列、集合、映射表等
这些容器分为序列式容器和关联式容器
序列式容器 :强调值的排序,序列式容器中的每个元素均有固定的位置
关联式容器 :二叉树结构体,各元素之间没有严格上的物理上的顺序关系
算法 :问题之解法也
有限的步骤,解决逻辑或数学上的问题,这一门学科我们叫做算法(Algorithms)
算法分为:质变算法和非质变算法
质变算法:是指运算过程中会更改区间内元素的内容。例如拷贝、查找、删除等等
非质变算法:是指在运算过程中不会更改区间内的元素内容,例如查找、
计数、遍历、寻找极值等等
迭代器 :容器和算法之间的的粘合剂
提供一种方法,使之能够依序寻访某个容器所含的各个元素,而又无需暴露该容器的内部表示方式。
每个容器都有自己专属的迭代器。
迭代器的使用非常类似于指针,初学阶段我们可以先理解迭代器为指针。
迭代器种类:
常用的容器中迭代器种类为双向迭代器,和随机访问迭代器。
容器算法迭代器初识 了解STL容器、算法、迭代器概念之后,我们利用代码感受STL的魅力
STL中最常用的容器为Vector,可以理解为数组,下面我们将学习如何向这个容器中插入数据、并遍历这个容器
Vector存放内置数据类型 容器:vector
算法:for_each
迭代器:vector::iterator
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 #include <iostream> #include <vector> #include <algorithm>//标准算法的头文件 using namespace std ;void myPrint (int val) { cout << val << endl ; } void test01 () { vector <int >v; v.push_back(10 ); v.push_back(20 ); v.push_back(30 ); v.push_back(40 ); for_each(v.begin(), v.end(), myPrint); } int main (void ) { test01(); system("pause" ); return 0 ; }
Vector存放自定义数据类型 学习目标 :vector中存放自定义数据类型,并打印输出
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 #include <iostream> #include <vector> #include <string> #include <algorithm>//标准算法的头文件 using namespace std ;class Person { public : Person(string name,int age ) { this ->m_Age = age; this ->m_Name = name; } string m_Name; int m_Age; }; void test01 () { vector <Person>v; Person p1 ("a1" , 10 ) ; Person p2 ("a2" , 10 ) ; Person p3 ("a3" , 10 ) ; Person p4 ("a4" , 10 ) ; Person p5 ("a5" , 10 ) ; 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 << "姓名:" << it->m_Name << "年龄:" << it->m_Age << endl ; } } void test02 () { vector <Person*>v; Person p1 ("a1" , 10 ) ; Person p2 ("a2" , 10 ) ; Person p3 ("a3" , 10 ) ; Person p4 ("a4" , 10 ) ; Person p5 ("a5" , 10 ) ; 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 << "姓名:" << (*it)->m_Name << "年龄:" << (*it)->m_Age << endl ; } } int main (void ) { test01(); test02(); system("pause" ); return 0 ; }
Vector容器嵌套容器 学习目标 :容器中嵌套容器,我们将所有数据进行遍历输出
(类似二维数组)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std ;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++) { for (vector <int >::iterator vit = (*it).begin(); vit != (*it).end(); vit++) { cout << *vit << " " ; } cout << endl ; } } int main (void ) { test01(); system("pause" ); return 0 ; }
STL常用容器 string容器 string基本概念 本质 :
string是C++风格的字符串,而string本质上是一个类
string和char*区别 :
char*是一个指针
string是一个类,类内部封装了char*,管理者个字符串,是一个char&型的容器
特点 : strint类内部封装了很多成员方法
例如;查找find,拷贝copy,删除delete,替换replace,插入insert
string管理char*所分配的内存,不用但是赋值越界和取值越界等,由类内部进行负责
string构造函数 构造函数原型
string()创建一个空的字符串
string(const char* s)使用字符串s初始化
string(const string& str)使用一个string对象初始化另一个string对象
string(int n,char c)使用n个字符c初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std ;void test01 () { string s1; const char * str = "hellow world" ; string s2 (str) ; cout << "s2:" <<s2 << endl ; string s3 (s2) ; cout << "s3" << s3 << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
string赋值操作 功能描述 ;
赋值的函数原型 :
string& operator = (const char* s)char*类型字符串 赋值给当前的字符串
string& operator = (const string &s)把字符串s赋给当前的字符串
string& operator = (char c)把字符赋值给当前的字符串
string& assign(const char* s)把字符串s赋值给当前的字符串
string& assign(const char*s,int n)把字符串s的当前n个字符赋给当前的字符串
string& assign(const string &s)把字符串s赋给当前字符串
string& assign(int n,char c)用n个字符c赋给当前字符串
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std ;void test01 () { string str1; str1 = "hello world" ; cout << "str1=" << str1 << endl ; string str2; str2 = str1; cout << "str2=" << str2 << endl ; string str3; str3 = 'c' ; 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(10 , 'w' ); cout << "str7=" << str7 << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : string赋值方式很多,operator=这种方式是比较实用的。
string字符串拼接 功能描述 :
函数原型 :
string& operator+=(const char* str)重载+=操作符
string& operator+=(const char c)重载+=操作符
string& operator+=(const string& str)重载+=操作符
string& append(const char* s)把字符串s连接到当前字符串结尾
string& append(const char* s,int n)把字符串s的前n个字符连接到当前字符串的结尾
string& append(const string &s)同operator+=(const string& str)
string& append(const string &s,int pos,int n)把字符串s中从pos开始的n个字符连接到字符串结尾
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std ;void test01 () { string str1 = "你" ; str1 += "是伞兵" ; cout << "str1=" << str1<< endl ; str1 += '?' ; cout << "str1=" << str1 << endl ; string str2 = "zbc" ; str1 += str2; cout << "str1=" << str1 << endl ; string str3 = "You" ; str3.append(" SB" ); cout << "str3=" << str3 << endl ; str3.append("hahaha hahaha" , 4 ); cout << "str3=" << str3 << endl ; str3.append(str2); cout << "str3=" << str3 << endl ; str3.append(str2, 0 , 1 ); cout << "str3=" << str3 << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : 字符串拼接的重载版本很多,初学阶段记住几种即可。
string查找和替换 功能描述 :
查找:查找指定位置字符串是否存在
替换:在指定的位置替换字符串
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std ;void test01 () { string str1 = "abcdefg" ; int pos1 = str1.find("de" ); cout << "pos1=" << pos1 << endl ; int pos2 = str1.find("z" ); cout << "pos2=" << pos2<< endl ; pos1 = str1.rfind("ab" ); cout << "pos1=" << pos1 << endl ;; } void test02 () { string str2 = "abcdef" ; str2.replace(1 , 3 , "1111" ); cout << "str2=" << str2 << endl ; } int main (void ) { test01(); test02(); system("pause" ); return 0 ; }
总结 :
find查找是从左往右,rfind从右往左
find找到字符串后返回查找的第一个字符位置,找不到返回1
replace在替换时,要指定从哪个位置起,多少个字符,替换成什么样的字符串
string字符串比较 功能描述 : 字符串之间的比较
比较方式 :
字符串比较是按字符的ASCII码进行对比
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 #include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std ;void test01 () { string str1 = "zello" ; string str2 = "hello" ; if (str1.compare(str2) == 0 ) { cout << "相等" << endl ; } else if (str1.compare(str2) > 0 ) { cout << "str1大" << endl ; } else { cout << "str2大" << endl ; } } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : 字符串对比主要是用于比较两个字符串是否相等,判断谁大谁小的意义并不是很大。
string字符读取 string中单个字符存取方式有两种
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std ;void test01 () { string str1 = "hello" ; for (int i = 0 ; i < str1.size(); i++) { cout << str1[i] << " " ; } cout << endl ; for (int i = 0 ; i < str1.size(); i++) { cout << str1.at(i) << " " ; } cout << endl ; str1[0 ] = 'z' ; cout << str1 << endl ; str1.at(0 ) = 'x' ; cout << str1 << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
string字符串中单个字符存取有两种方式,利用[]或at
string插入和删除 功能描述 :
对string字符串进行插入和删除字符操作。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <iostream> #include <string> #include <vector> #include <algorithm> using namespace std ;void test01 () { string str = "hello" ; str.insert(1 , "111" ); cout << "str = " << str << endl ; str.erase(1 ,3 ); cout << "str = " << str << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : 插入和删除的起始下标都是从0开始。
string字串 功能描述 : 从字符串中获得想要的字串。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 #include <iostream> #include <string> using namespace std ;void test01 () { string str = "abcdef" ; string subStr = str.substr(1 , 3 ); cout << "subStr=" << subStr << endl ; } void test02 () { string email = "zhangsan@qq.com" ; int pos = email.find("@" ); string usrName = email.substr(0 , pos); cout << usrName << endl ; } int main (void ) { test01(); test02(); system("pause" ); return 0 ; }
总结 : 灵活的运用求字串功能,可以在实际开发中获取有效的信息。
vector容器 vector基本概念 功能 : vector数据结构和数组非常相似,也称为单端数组
vector与普通数组区别 :
不同之处在于数组是静态空间,而vector可以动态扩展
动态扩展 :
并不是在原空间之后续接新空间,而是找更大的内存空间,然后将原数据拷贝到新空间,释放原空间。
vector构造函数 功能描述 : 创建vector容器
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #include <iostream> #include <string> #include <algorithm> #include <vector> using namespace std ;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); vector <int >v2(v1.begin(), v1.end()); printVector(v2); vector <int >v3(10 , 100 ); printVector(v3); vector <int >v4(v3); printVector(v4); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : vector的多种构造方式没有可比性,灵活使用即可。
vector赋值操作 功能描述 : 给vector容器进行赋值
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #include <iostream> #include <string> #include <algorithm> #include <vector> using namespace std ;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); 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 (void ) { test01(); system("pause" ); return 0 ; }
总结 : vector赋值方式比较简单,使用operator=,或者assign都可以。
vector容量和大小 功能描述 : 对vector容器的容量和大小操作
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 #include <iostream> #include <string> #include <algorithm> #include <vector> using namespace std ;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 << "空" << endl ; } else { cout << "不空" << endl ; } cout << "v1的容量=" << v1.capacity() << endl ; cout << "v1的大小=" << v1.size() << endl ; v1.resize(15 ,100 ); PrintVector(v1); v1.resize(5 ); PrintVector(v1); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
判断是否为空——empty
返回元素个数——size
返回容器容量——capacity
重新指定大小——resize
vector插入和删除 功能描述 : 对vector容器进行插入、删除操作
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include <iostream> #include <vector> #include <algorithm> using namespace std ;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.clear(); PrintVector(v1); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
尾插——push_back
尾删——pop_back
插入——insert(位置迭代器)
删除——erase(位置迭代器)
清空——clear
vector数据存取 功能描述 : 对vector中的数据进行存取操作
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <iostream> #include <vector> #include <algorithm> using namespace std ;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.front() << endl ; cout << "最后一个元素=" << v1.back()<<endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
除了用迭代器获取vector中元素,[]和at也可以
front返回容器第一个元素
back返回容器最后一个元素
vector互换容器 功能描述 ; 实现两个容器内元素进行互换
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 #include <iostream> #include <vector> #include <algorithm> using namespace std ;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; cout << "交换前" << endl ; for (int i = 0 ; i < 10 ; i++) { v1.push_back(i); } PrintVector(v1); vector <int >v2; for (int i = 10 ; i > 0 ; i--) { v2.push_back(i); } PrintVector(v2); cout << "交换后" << endl ; v1.swap(v2); PrintVector(v1); PrintVector(v2); } void test02 () { vector <int >v; for (int i = 0 ; i < 10000 ; i++) { v.push_back(i); } cout << "容量" << v.capacity() << endl ; cout << "大小" << v.size() << endl ; cout << endl ; v.resize(3 ); cout << "容量" << v.capacity() << endl ; cout << "大小" << v.size() << endl ; vector <int >(v).swap(v); cout << endl ; cout << "容量" << v.capacity() << endl ; cout << "大小" << v.size() << endl ; } int main (void ) { test01(); test02(); system("pause" ); return 0 ; }
总结 : swap可以使两个容器互换,可以达到实用的收缩内存效果。
vector预留空间 功能描述 : 减少vector在动态内存扩容时的扩展次数
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <iostream> #include <vector> #include <algorithm> using namespace std ;void test01 () { vector <int >v1; int num = 0 ; int * p = NULL ; for (int i = 0 ; i < 100000 ; i++) { v1.push_back(i); if (p != &v1[0 ]) { p = &v1[0 ]; num++; } } cout << num << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : 如果数据量较大,可以一开始利用reserve预留空间。
deque容器 deque容器基本概念 功能 : 双端数组,可以对头端进行插入删除操作
deque与vector区别 :
vector对于头部的插入删除效率低,数据量越大,效率越低
deque相对而言,对头部的插入删除速度会比vector快
vector访问元素时的速度会比deque快,这和两者内部实现有关
deque的内部工作原理
deque内部有个中控器,维护每段缓冲区中的内容,缓冲区中存放真实数据。
中控器维护的是每个缓冲区的地址,使得使用deque时像一片连续的内存空间。
deque容器的迭代器也是支持随机访问的。
deque构造函数 功能描述 :
deque容器构造
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include <iostream> #include <deque> using namespace std ;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); deque <int >d2(d1.begin(), d1.end()); PrintDeque(d2); deque <int >d3(10 , 100 ); PrintDeque(d3); deque <int >d4(d3); PrintDeque(d4); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : deque容器和vector容器的构造方式几乎一致,灵活使用即可。
deque赋值操作 功能描述 : 给deque容器进行赋值
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <iostream> #include <deque> using namespace std ;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); 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 (void ) { test01(); system("pause" ); return 0 ; }
总结 : deque赋值操作也与vector相同,需熟练掌握。
deque大小操作 功能描述 : 对deque容器的大小进行操作
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include <iostream> #include <deque> using namespace std ;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); if (d1.empty()) { cout <<"空" <<endl ; } else { cout <<"不空" <<endl ; } cout << "大小" << d1.size() << endl ; d1.resize(15 ,1 ); PrintDeque(d1); d1.resize(5 ); PrintDeque(d1); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
deque没有容量概念
判断是否为空——empty
返回元素个数——size
重新指定个数——resize
deque插入和删除 功能描述 : 向deque容器中插入和删除数据
函数原型 : 两端插入操作:
指定位置操作:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 #include <iostream> #include <deque> using namespace std ;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_front(100 ); d1.push_front(200 ); PrintDeque(d1); d1.pop_back(); PrintDeque(d1); d1.pop_front(); PrintDeque(d1); } void test02 () { deque <int >d2; d2.push_back(10 ); d2.push_back(20 ); d2.push_front(100 ); d2.push_front(200 ); PrintDeque(d2); d2.insert(d2.begin(), 1000 ); PrintDeque(d2); d2.insert(d2.begin(), 2 ,10000 ); PrintDeque(d2); deque <int >d3; d3.push_back(1 ); d3.push_back(2 ); d3.push_back(3 ); d2.insert(d2.begin(), d3.begin(), d3.end()); PrintDeque(d2); } void test03 () { deque <int >d4; d4.push_back(10 ); d4.push_back(20 ); d4.push_front(100 ); d4.push_front(200 ); PrintDeque(d4); deque <int >::iterator it = d4.begin(); it++; d4.erase(it); PrintDeque(d4); d4.erase(d4.begin(), d4.end()); PrintDeque(d4); d4.clear(); PrintDeque(d4); } int main (void ) { test01(); test02(); test03(); system("pause" ); return 0 ; }
总结 :
插入和删除提供的位置是迭代器!
尾插——push_back
尾删——pop_back
头插——push_front
头删——pop_front
deque数据存取 功能描述 : 对deque中的数据的存取操作
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #include <iostream> #include <deque> using namespace std ;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 < 3 ; i++) { d1.push_back(i); } d1.push_front(100 ); d1.push_front(200 ); d1.push_front(300 ); for (int i = 0 ; i < d1.size(); i++) { cout << d1[i] << " " ; } cout << endl ; for (int i = 0 ; i < d1.size(); i++) { cout << d1.at(i) << " " ; } cout << endl ; cout << "第一个元素=" << d1.front() << endl ; cout << "最后一个元素=" << d1.back() << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
除了用迭代器获取deque容器中元素
front返回容器第一个元素
back返回容器最后一个元素
deque排序 功能描述 : 利用算法实现对deque容器进行排序
算法 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include <iostream> #include <deque> #include <algorithm>//标准算法头文件 using namespace std ;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_front(100 ); d1.push_front(200 ); d1.push_front(300 ); PrintDeque(d1); cout << "排序后" << endl ; sort(d1.begin(), d1.end()); PrintDeque(d1); } int main (void ) { test01(); system("pause" ); return 0 ; }
案例——评委打分 案例描述 有五名选手,选手ABCDE,10个评委分别对每一个选手打分,去除最高分和最低分,取平均分。
实现步骤
创建五名选手,放到vector中
遍历vector容器,取出来每一个选手,执行for循环,可以把10个评分打分存到deque容器中
sort算法对deque容器中分数排序,去除最高分和最低分
deque容器遍历一遍,累加总分
获取平均分
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 #include <iostream> #include <string> #include <vector> #include <deque> #include <algorithm> #include <ctime> using namespace std ;class Person { public : Person(string name, int score) { this ->m_Name = name; this ->m_Score = score; } string m_Name; int m_Score; }; void CreatPerson (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) ; v.push_back(p); } } void setScroe (vector <Person>& v) { for (vector <Person>::iterator it = v.begin(); it != v.end(); it++) { deque <int >d; for (int i = 0 ; i < 10 ; i++) { int score = rand() % 41 + 60 ; d.push_back(score); } sort(d.begin(), d.end()); d.pop_front(); d.pop_back(); int sum = 0 ; for (deque <int >::iterator dit = d.begin(); dit != d.end(); dit++) { sum += *dit; } int avg = sum / 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 (void ) { srand((unsigned int )time(NULL )); vector <Person>v; CreatPerson(v); setScroe(v); showScore(v); system("pause" ); return 0 ; }
stack容器 stack基本概念 概念 : stack是一种先进后出的数据结构,它只有一个出口。
栈中只有栈顶的元素才可以被外界使用,因此栈不允许有遍历行为。
栈可以判断容器是否为空。
栈可以返回元素个数。
栈中进入数据——进栈。
栈中弹出数据——出栈。
stack常用接口 功能描述 :
栈容器常用的对外接口。
构造函数 :
赋值操作 :
数据存取 :
大小操作 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <iostream> #include <stack> using namespace std ;void test01 () { stack <int >s; s.push(1 ); s.push(2 ); s.push(3 ); s.push(4 ); cout << "栈的大小:" << s.size() << endl ; while (!s.empty()) { cout << s.top() << endl ; s.pop(); } cout << "栈的大小:" << s.size()<< endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
入栈——push
出栈——pop
返回栈顶——top
判断栈是否为空——empty
返回栈大小——size
queue容器 queue容器基本概念 概念 : Queue是一种先进先出的数据结构,它有两个出口。
只有队头和队尾能被外界访问,因此不允许有遍历行为。
队列容器允许从一端新增元素,从另一端移除元素。
队列中进入数据——入队。
队列中出数据——出队。
queue常用接口 功能描述 : 栈容器常用的对外接口。
构造函数 :
赋值操作 :
数据存取 :
大小操作 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <iostream> #include <queue> #include <string> using namespace std ;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 ("s1" , 1 ) ; Person p2 ("s2" , 2 ) ; Person p3 ("s3" , 3 ) ; Person p4 ("s4" , 4 ) ; q.push(p1); q.push(p2); q.push(p3); q.push(p4); cout << "大小=" << q.size() << endl ; while (!q.empty()) { cout << q.front().m_Name <<" " << q.front().m_Age << endl ; q.pop(); } cout << "大小=" << q.size() << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
入队——push
出队——pop
返回队头元素——front
返回队尾元素——back
判断队是否为空——empty
返回队列大小——size
list容器 list基本概念 功能 :将数据进行链式存储
**链表(list)**:是一种物理存储单元上非连续的存储结构,数据元素的逻辑顺序是通过链表中的指针链接来实现的。
链表的组成:链表由一系列结点组成。
结点的组成:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域。
SLT中的链表是一个双向循环链表。
由于链表的存储方式并不是连续的内存空间,因此链表list中的迭代器只支持前移和后移,属于双向迭代器。
list的优点:
采用动态存储分配,不会造成内存浪费和溢出
链表执行插入和删除操作十分方便,修改指针即可,不需要移动大量元素
list的缺点:
链表灵活,但是空间(指针域)和时间(遍历)额外耗费较大。
list有一个重要的性质,插入操作和删除操作都不会造成原有list迭代器的失效,这在vector是不成立的。
总结 : STL中List和vector是两个最常用的容器,各有优缺点。
list构造函数 功能描述 : 创建list容器
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #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 << endl ; } void test01 () { list <int >l1; l1.push_back(1 ); l1.push_back(2 ); l1.push_back(3 ); l1.push_back(4 ); PrintList(l1); list <int >l2(l1.begin(), l1.end()); PrintList(l2); list <int >l3(l2); PrintList(l3); list <int >l4(10 , 100 ); PrintList(l4); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
list构造方式同其他几个STL常用容器,熟练掌握即可。
list赋值和交换 功能描述 : 给list容器进行赋值,以及交换list容器。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 #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 << endl ; } void test01 () { list <int >l1; l1.push_back(1 ); l1.push_back(2 ); l1.push_back(3 ); l1.push_back(4 ); PrintList(l1); list <int >l2; l2 = l1; PrintList(l2); list <int >l3; l3.assign(l2.begin(), l2.end()); PrintList(l3); list <int >l4; l4.assign(10 , 100 ); PrintList(l4); } void test02 () { list <int >l5; l5.push_back(1 ); l5.push_back(2 ); l5.push_back(3 ); l5.push_back(4 ); list <int >l6; l6.push_back(4 ); l6.push_back(3 ); l6.push_back(2 ); l6.push_back(1 ); cout << "交换前" << endl ; PrintList(l5); PrintList(l6); l5.swap(l6); cout << "交换后" << endl ; PrintList(l5); PrintList(l6); } int main (void ) { test01(); test02(); system("pause" ); return 0 ; }
总结 : list赋值和交换能够灵活运用即可。
list大小操作 功能描述 : 对list容器的大小进行操作。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #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 << endl ; } void test01 () { list <int >l1; l1.push_back(1 ); l1.push_back(2 ); l1.push_back(3 ); l1.push_back(4 ); PrintList(l1); if (l1.empty()) { cout << "空" << endl ; } else { cout << "不空" << endl ; cout << "元素个数=" << l1.size()<<endl ; } l1.resize(10 , 1000 ); PrintList(l1); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
判断是否为空——empty
返回元素个数——size
重新指定个数——resize
list插入和删除 功能描述 : 对list容器进行数据的插入和删除
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 #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 << endl ; } void test01 () { list <int >l1; l1.push_back(1 ); l1.push_back(2 ); l1.push_back(3 ); l1.push_back(4 ); l1.push_front(10 ); l1.push_front(20 ); PrintList(l1); l1.pop_back(); PrintList(l1); l1.pop_front(); PrintList(l1); list <int >::iterator it = l1.begin(); it++; l1.insert(it, 1000 ); PrintList(l1); it = l1.begin(); l1.erase(++it); PrintList(l1); l1.push_back(1000 ); l1.push_back(1000 ); l1.push_back(1000 ); PrintList(l1); l1.remove(1000 ); PrintList(l1); l1.clear(); PrintList(l1); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
尾插——push_back
尾删——pop_back
头插——push_front
头删——pop_front
插入——insert
删除——erase
移除——remove
清空——clear
list数据存取 功能描述 : 对list容器中数据进行存储。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #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 << endl ; } void test01 () { list <int >l1; l1.push_back(1 ); l1.push_back(2 ); l1.push_back(3 ); l1.push_back(4 ); cout << "第一个元素=" << l1.front() << endl ; cout << "最后一个元素=" << l1.back() << endl ; list <int >::iterator it = l1.begin(); it++; it--; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
list容器中不可以通过[]或者at方式访问数据
返回第一个元素——front
返回最后一个元素——back
list反转和排序 功能描述 : 将容器中的元素反转,以及将容器中的数据进行排序。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 #include <iostream> #include <list> #include <algorithm> using namespace std ;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(1 ); l1.push_back(2 ); l1.push_back(3 ); l1.push_back(4 ); cout << "反转前" << endl ; PrintList(l1); cout << "反转后" << endl ; l1.reverse(); PrintList(l1); } bool myCompare (int v1, int v2) { return v1 > v2; } void test02 () { list <int >l2; l2.push_back(20 ); l2.push_back(10 ); l2.push_back(50 ); l2.push_back(30 ); l2.push_back(40 ); cout << "排序前" << endl ; PrintList(l2); cout << "排序后" << endl ; l2.sort(); PrintList(l2); l2.sort(myCompare); PrintList(l2); } int main (void ) { test01(); test02(); system("pause" ); return 0 ; }
总结 :
反转——reverse
排序——sort(成员函数)
排序案例 案例描述 :将Person自定义类型进行排序,Person中属性有姓名、年龄、身高。
排序规则 :按照年龄进行升序,如果年龄相同则按照身高进行降序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 #include <iostream> #include <list> #include <string> using namespace std ;class Person { public : Person(string name, int age, int height) { this ->m_Age = age; this ->m_Height = height; this ->m_Name = name; } 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 test01 () { list <Person>L; Person p1 ("s11" ,23 ,166 ) ; Person p2 ("s12" ,23 ,156 ) ; Person p3 ("s13" ,23 ,178 ) ; Person p4 ("s14" ,33 ,172 ) ; Person p5 ("s15" ,43 ,190 ) ; Person p6 ("s16" ,45 ,175 ) ; 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 << it->m_Name <<" " << it->m_Age <<" " << it->m_Height << endl ; } cout << "排序后" << endl ; L.sort(comparePerson); for (list <Person>::iterator it = L.begin(); it != L.end(); it++) { cout << it->m_Name << " " << it->m_Age << " " << it->m_Height << endl ; } } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
对于自定义数据类型,必须要指定排序规则,否则编译器不知道如何进行排序
高级排序只是在排序规则上再进行一次逻辑规则制定,并不复杂。
set/multiset容器 set基本概念 简介 : 所有元素都会在插入时被自动排序。
本质 : set/multiset属于关联式容器,底层结构是用二叉树实现。
set和multiset区别 :
set不允许容器中有重复的元素。
multiset允许容器中有重复的元素
set构建和赋值 功能描述 :
创建set容器以及赋值。
构造 :
赋值 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <iostream> #include <set> using namespace std ;void PrintSet (set <int > &s) { for (set <int >::iterator it = s.begin(); it != s.end(); it++) { cout << *it << " " ; } cout << endl ; } void test01 () { set <int >s1; s1.insert(30 ); s1.insert(20 ); s1.insert(10 ); s1.insert(40 ); PrintSet(s1); set <int >s2(s1); PrintSet(s2); set <int >s3; s3 = s2; PrintSet(s3); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
set容器插入数据时用insert
set容器插入的数据会自动排序
set大小和交换 功能描述 : 统计set容器大小以及交换set容器。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 #include <iostream> #include <set> using namespace std ;void PrintSet (set <int > &s) {for (set <int >::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); if (s1.empty()) { cout << "空" << endl ; } else { cout << "不空" << endl ; cout << "大小:" << s1.size() << endl ; } } void test02 () { set <int >s2; set <int >s3; s2.insert(100 ); s2.insert(200 ); s2.insert(300 ); s3.insert(1 ); s3.insert(2 ); s3.insert(3 ); cout << "交换前:" << endl ; PrintSet(s2); PrintSet(s3); s2.swap(s3); cout << "交换后:" << endl ; PrintSet(s2); PrintSet(s3); } int main (void ) { test01(); test02(); system("pause" ); return 0 ; }
总结 :
统计大小——size
判断是否为空——empty
交换容器——swap
set插入和删除 功能描述 : set容器进行插入数据和删除数据
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 #include <iostream> #include <set> using namespace std ;void PrintSet (set <int > &s) {for (set <int >::iterator it = s.begin(); it != s.end(); it++){ cout << *it << " " ; } cout << endl ;} void test01 () { set <int >s1; s1.insert(2 ); s1.insert(1 ); s1.insert(3 ); s1.insert(4 ); PrintSet(s1); s1.erase(s1.begin()); PrintSet(s1); s1.erase(3 ); PrintSet(s1); s1.erase(s1.begin(), s1.end()); PrintSet(s1); s1.clear(); PrintSet(s1); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
插入——insert
删除——erase
清空——clear
ser查找和统计 功能描述 : 对set容器进行查找数据以及统计数据
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #include <iostream> #include <set> using namespace std ;void PrintSet (set <int > &s) {for (set <int >::iterator it = s.begin(); it != s.end(); it++){ cout << *it << " " ; } cout << endl ;} void test01 () { set <int >s1; s1.insert(1 ); s1.insert(2 ); s1.insert(3 ); s1.insert(4 ); set <int >::iterator pos = s1.find(3 ); if (pos != s1.end()) { cout << "找到" << *pos << endl ; } else { cout << "没找到" << endl ; } int num = s1.count(3 ); cout << num << "个" << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
查找——find(返回的是迭代器)
统计——count(对于set,结果为0或者1)
set和multiset区别 学习目标 : 掌握set和multiset的区别
区别 :
set不可以插入重复数据,而multiset可以
set插入数据的同时会返回插入结果,表示插入是否成功
multiset不会检测数据,因此可以插入重复数据
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 #include <iostream> #include <set> using namespace std ;void PrintMultiSet (multiset <int >& ms) { for (multiset <int >::iterator it = ms.begin(); it != ms.end(); it++) { cout << *it << " " ; } cout << endl ; } void test01 () { set <int >s1; pair <set <int >::iterator,bool >ret = s1.insert(10 ); if (ret.second) { cout << "插入成功" << endl ; } else { cout << "插入失败" << endl ; } ret = s1.insert(10 ); if (ret.second) { cout << "插入成功" << endl ; } else { cout << "插入失败" << endl ; } multiset <int >ms; ms.insert(10 ); ms.insert(10 ); PrintMultiSet(ms); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
如果不允许插入重复数据可以利用set
如果需要插入重复数据利用multiset
pair对组创建 功能描述 : 成对出现的数据,利用对组可以返回两个数据。
两种创建方式 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 #include <iostream> #include <string> using namespace std ;void test01 () { pair <string , int >p("Tom" , 11 ); cout << p.first <<" " << p.second << endl ; pair <string , int >p2 = make_pair ("Jerry" , 12 ); cout << p2.first << " " << p2.second << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : 两种方式都可以创建对组,记住一种即可。
set容器排序 学习目标 : set容器默认排序规则为从小到大,掌握如何改变排序规则。
主要技术点 : 利用仿函数,可以改变排序顺序。
内置类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <iostream> #include <set> using namespace std ;class MyCompare { public : bool operator () (int v1,int v2) const { return v1 > v2; } }; void test01 () { set <int ,MyCompare>s1; s1.insert(10 ); s1.insert(20 ); s1.insert(30 ); s1.insert(40 ); for (set <int ,MyCompare>::iterator it = s1.begin(); it != s1.end(); it++) { cout << *it << " " ; } cout << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
自定义类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #include <iostream> #include <set> #include <string> using namespace std ;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 () (const Person& p1, const Person& p2) const { return p1.m_Age > p2.m_Age; } }; void test01 () { set <Person, Mycompare>s1; Person p1 ("s1" ,11 ) ; Person p2 ("s2" ,22 ) ; Person p3 ("s3" ,33 ) ; Person p4 ("s4" ,44 ) ; s1.insert(p1); s1.insert(p2); s1.insert(p3); s1.insert(p4); for (set <Person, Mycompare>::iterator it = s1.begin(); it != s1.end(); it++) { cout << it->m_Name << " " << it->m_Age << endl ; } } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
map/multimap容器 map基本概念 简介 :
map中所有元素都是pair
pair中第一个元素为key(键值),起到索引作用,第二个元素为value(实值)
所有元素都会根据元素的键值自动排序
本质 : map/multimap属于关联式容器,底层结构是用二叉树实现。
优点 :
可以根据key值快速找到value值
区别 : map和multimap区别
map不允许容器中有重复key值元素
multimap允许容器中有重复key值元素
map构造和赋值 功能描述 : 对map容器进行构造和赋值操作。
函数原型 :构造 :
赋值 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include <iostream> #include <map> using namespace std ;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 << " " ; } cout << endl ; } void test01 () { map <int , int >m1; m1.insert(pair <int , int >(1 , 10 )); m1.insert(pair <int , int >(2 , 20 )); m1.insert(pair <int , int >(3 , 30 )); m1.insert(pair <int , int >(4 , 40 )); PrintMap(m1); map <int , int >m2(m1); PrintMap(m1); map <int , int >m3; m3 = m2; PrintMap(m3); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : map中所有元素都是成对出现,插入数据时要使用对组。
map大小和交换 功能描述 : 统计map容器大小以及交换map容器
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 #include <iostream> #include <map> using namespace std ;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 << " " ; } cout << endl ; } void test01 () { map <int , int >m1; m1.insert(pair <int , int >(1 , 10 )); m1.insert(pair <int , int >(2 , 20 )); m1.insert(pair <int , int >(3 , 30 )); m1.insert(pair <int , int >(4 , 40 )); PrintMap(m1); if (m1.empty()) { cout << "空" << endl ; } else { cout << "不空" << endl ; cout << "大小=" << m1.size() << endl ; } map <int , int >m2; m2.insert(pair <int , int >(10 , 1 )); m2.insert(pair <int , int >(20 , 2 )); m2.insert(pair <int , int >(30 , 3 )); m2.insert(pair <int , int >(40 , 4 )); cout << "交换前" << endl ; PrintMap(m1); PrintMap(m2); cout << "交换后" << endl ; m1.swap(m2); PrintMap(m1); PrintMap(m2); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
统计大小——size
判断是否为空——empty
交换容器——swap
map插入和删除 功能描述 : map容器进行插入数据和删除数据
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include <iostream> #include <map> using namespace std ;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 >m1; m1.insert(pair <int , int >(1 , 10 )); m1.insert(make_pair (2 , 20 )); m1.insert(map <int , int >::value_type(3 , 30 )); m1[4 ] = 40 ; cout << m1[4 ] << endl ; PrintMap(m1); m1.erase(m1.begin()); PrintMap(m1); m1.erase(3 ); PrintMap(m1); m1.erase(m1.begin(), m1.end()); PrintMap(m1); m1.clear(); PrintMap(m1); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
map插入方式很多,记住其一即可
插入——insert
删除——erase
清空——clear
map查找和统计 功能描述 : 对map容器进行查找和数据以及统计数据
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <iostream> #include <map> using namespace std ;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 >m1; m1.insert(pair <int , int >(1 , 10 )); m1.insert(pair <int , int >(2 , 20 )); m1.insert(pair <int , int >(3 , 30 )); map <int , int >::iterator pos = m1.find(3 ); if (pos != m1.end()) { cout << "找到了" <<pos->first<<" " <<pos->second<< endl ; } else { cout << "没找到" << endl ; } int num = m1.count(3 ); cout << num << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
查找——find(返回的是迭代器)
统计——cout(对于map,结果为0或1)
map容器排序 学习目标 : map容器默认排序规则为按照key值进行从小到大排序,掌握如何改变排序规则。
主要技术点 : 利用仿函数,可以改变排序规则。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 #include <iostream> #include <map> using namespace std ;class MyCompare { public : bool operator () (int v1,int v2) const { return v1 > v2; } }; void PrintMap (map <int , int , MyCompare>& m) { for (map <int , int , MyCompare>::iterator it = m.begin(); it != m.end(); it++) { cout << "key=" << it->first << " " << "value=" << it->second << endl ; } cout << endl ; } void test01 () { map <int , int ,MyCompare>m1; m1.insert(make_pair (1 , 10 )); m1.insert(make_pair (2 , 20 )); m1.insert(make_pair (3 , 30 )); m1.insert(make_pair (4 , 40 )); m1.insert(make_pair (5 , 50 )); PrintMap(m1); } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
利用仿函数可以指定map容器的排序规则
对于自定义数据类型,map必须要指定排序规则,同set容器
案例——员工分组 案例描述
公司今天招聘了10个员工(ABCDEFGHIJ),10名员工进入公司之后,需要指派员工在哪个部门工作。
员工信息有:姓名、工资组成、部门分为:策划、美术、研发
通过multimap进行信息的插入 key(部门编号)value(员工)
分部门显示员工信息
实现步骤
创建10名员工,放到vector中
遍历vector容器,取出每个员工,进行随机分组
分组后,将员工部门编号作为key,具体员工作为value,放入到multimap容器中
分部门显示员工信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 #include <iostream> #include <map> #include <vector> #include <string> #include <ctime> using namespace std ;#define CEHUA 0 #define MEISHU 1 #define YANFA 2 class Worker { public : string m_Name; int m_Salary; }; void CreatWorker (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 ; 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 ; m.insert(make_pair (deptId, *it)); } } void ShowWorkerByGroup (multimap <int ,Worker> &m) { 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 ; 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 ; 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 (void ) { srand((unsigned int )time(NULL )); vector <Worker>vWorker; CreatWorker(vWorker); multimap <int , Worker>mWorker; SetGroup(vWorker, mWorker); ShowWorkerByGroup(mWorker); system("pause" ); return 0 ; }
STL函数对象 函数对象 函数对象概念 概念 :
重载函数调用操作符的类,其对象也称为函数对象
函数对象使用重载()时,行为类似函数调用,也叫仿函数
本质 :
函数对象(仿函数)是一个类,不是一个函数。
函数对象使用 特点 :
函数对象在使用时,可以像普通函数那样调用,可以有参数,可以有返回值
函数对象超出普通函数的概念,函数对象可以有自己的状态
函数对象可以作为参数传递
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 #include <iostream> #include <string> using namespace std ;class MyAdd { public : int operator () (int v1, int v2) { return v1 + v2; } }; void test01 () { 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" ); myprint("hello world" ); myprint("hello world" ); cout << "MyPrint调用次数为:" << myprint.count << endl ; } void doPrint (MyPrint& mp, string test) { mp(test); } void test03 () { MyPrint myPrint; doPrint(myPrint, "hello c++" ); } int main (void ) { test01(); test02(); test03(); system("pause" ); return 0 ; }
总结 :
仿函数写法非常灵活,可以作为参数进行传递。
谓词 谓词概念 概念 :
返回bool类型的仿函数称为谓词
如果operator()接受一个参数,那么叫做一元谓词
如果operator()接收两个参数,那么叫做二元谓词
一元谓词 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 #include <iostream> #include <vector> #include <algorithm> using namespace std ;class CreaterFive { public : bool operator () (int val) { return val > 5 ; } }; void test01 () { vector <int >v; for (int i = 0 ; i < 10 ; i++) { v.push_back(i); } vector <int >::iterator pos = find_if(v.begin(), v.end(), CreaterFive()); if (pos == v.end()) { cout << "未找到" << endl ; } else { cout << "找到了,大于5的数字为:" << *pos << endl ; } } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : 参数中只有一个的谓词,叫做一元谓词
二元谓词 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include <iostream> #include <vector> #include <algorithm> using namespace std ;class MyCompare { public : bool operator () (int val1,int val2) { return val1 > val2; } }; 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 << endl ; sort(v.begin(), v.end(),MyCompare()); for (vector <int >::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " " ; } cout << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
参数只有两个的谓词,称为二元谓词。
内建函数对象 内建函数对象意义 概念 : STL内建了一些函数对象
分类 :
用法 :
这些仿函数所产生的对象,用法和一般函数完全相同
使用内建函数对象,需要引入头文件#include< functional>
算数仿函数 功能描述 :
实现四则运算
其中negate是一元运算,其它都是二元运算
仿函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <iostream> #include <vector> #include <algorithm> #include <functional>//内建函数对象头文件 using namespace std ;void test01 () { negate<int >n; cout << n(50 ) << endl ; } void test02 () { plus<int >p; cout << p(10 , 20 ) << endl ; } int main (void ) { test01(); test02(); system("pause" ); return 0 ; }
总结 : 使用内建函数对象时,需要引入头文件#include< functional>
关系仿函数 功能描述 : 实现关系对比
仿函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 #include <iostream> #include <vector> #include <algorithm> #include <functional> using namespace std ;class MyCompare { public : bool operator () (int v1,int v2) { return v1 > v2; } }; void test01 () { vector <int >v; v.push_back(1 ); v.push_back(3 ); v.push_back(4 ); v.push_back(2 ); v.push_back(5 ); for (vector <int >::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " " ; } cout << endl ; sort(v.begin(),v.end(), greater<int >()); for (vector <int >::iterator it = v.begin(); it != v.end(); it++) { cout << *it << " " ; } cout << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
关系仿函数最常用的就是greater<>大于
逻辑仿函数 功能描述 : 实现逻辑运算
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 #include <iostream> #include <vector> #include <algorithm> #include <functional> using namespace std ;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 << endl ; vector <bool >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 << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : 逻辑仿函数实际应用较少,了解即可。
STL常用算法 概述 :
算法主要是由头文件< algorithm >< functional > < numeric >组成
< algorithm >是所有STL头文件中最大的一个,范围涉及到比较、交换、查找、遍历操作、复制、修改等等。
< functional >定义了一些模板类,用以声明函数对象
< numeric >体积很小,只包括几个在序列上面进行简单数据运算的模板函数
常用遍历算法 学习目标 : 掌握常用的遍历算法
算法简写 :
for_each 功能描述 : 实现遍历容器
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 #include <iostream> #include <vector> #include <algorithm> #include <functional> using namespace std ;void Print01 (int val) { cout << val<<" " ; } class Print02 { public : void operator () (int val) { cout << val << " " ; } }; void test01 () { 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()); cout << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : for_each在实际开发中是最常用的遍历算法,需要熟练掌握。
功能描述 :
搬运容器到另一个容器中。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 #include <iostream> #include <vector> #include <algorithm> #include <functional> using namespace std ;class TransForm { public : int operator () (int val) { return val + 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(v.begin(), v.end(), vTarget.begin(), TransForm()); for_each(vTarget.begin(), vTarget.end(), MyPrint()); cout << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : 搬运的目标容器必须提前开辟空间,否则无法正常搬运。
常用查找算法 学习目标 : 掌握常用的查找算法
算法简介 :
find 功能描述 : 查找指定元素,找到返回指定元素的迭代器,找不到返回结束迭代器end()。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 #include <iostream> #include <vector> #include <algorithm> #include <functional> #include <string> using namespace std ;class Person { public : Person(string name,int age) { this ->m_Age = age; this ->m_Name = name; } bool operator ==(const Person& p) { if (this ->m_Age == p.m_Age && this ->m_Name == p.m_Name) { return true ; } else { return false ; } } string m_Name; string m_Age; }; void test01 () { vector <int >v; for (int i = 0 ; i < 10 ; i++) { v.push_back(i); } vector <int >::iterator it = find(v.begin(), v.end(), 5 ); if (it == v.end()) { cout << "没找到" << endl ; } else { cout << "找到" << *it << endl ; } } void test02 () { vector <Person>V; Person p1 ("1" ,11 ) ; Person p2 ("2" ,22 ) ; Person p3 ("3" ,33 ) ; Person p4 ("4" ,44 ) ; 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 << "没找到" << endl ; } else { cout << "找到" << it->m_Name << " " << it->m_Age << endl ; } } int main (void ) { test01(); test02(); system("pause" ); return 0 ; }
总结 : 利用find可以在容器中找指定的元素,返回值是迭代器。
find_if 功能描述 :
按条件查找元素。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 #include <iostream> #include <vector> #include <algorithm> #include <functional> #include <string> using namespace std ;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); } vector <int >::iterator it = find_if(v.begin(), v.end(), GreaterFive()); if (it == v.end()) { cout << "没找到" << endl ; } else { cout << "找到了" << *it << endl ; } } class Person { public : Person(string name,int age) { this ->m_Age = age; this ->m_Name = name; } 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 ("1" ,11 ) ; Person p2 ("2" ,22 ) ; Person p3 ("3" ,33 ) ; Person p4 ("4" ,44 ) ; 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 << "没找到" << endl ; } else { cout << "找到了" << it->m_Name<<" " <<it->m_Age << endl ; } } int main (void ) { test01(); test02(); system("pause" ); return 0 ; }
adjacent_find 功能描述 : 查找相邻重复元素。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <iostream> #include <vector> #include <algorithm> #include <functional> using namespace std ;void test01 () { vector <int >v; v.push_back(0 ); v.push_back(2 ); v.push_back(1 ); v.push_back(2 ); v.push_back(7 ); v.push_back(3 ); v.push_back(3 ); vector <int >::iterator it = adjacent_find(v.begin(), v.end()); if (it == v.end()) { cout << "没找到" << endl ; } else { cout << "找到相邻重复元素" << *it << endl ; } } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : 面试题中如果出现查找相邻重复元素,记得用STL中的adjacent_find算法
binary_search 功能描述 : 查找指定元素是否存在。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <iostream> #include <vector> #include <algorithm> #include <functional> using namespace std ;void test01 () { vector <int >v; for (int i = 0 ; i < 10 ; i++) { v.push_back(i); } bool ret = binary_search(v.begin(), v.end(),9 ); if (ret) { cout << "找到了" << endl ; } else { cout << "没找到" << endl ; } } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 “ 二分查找法效率很高,值得注意的是查找的容器中元素必须得是有序序列,否则结果未知。
count 功能描述 : 统计元素个数。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 #include <iostream> #include <vector> #include <algorithm> #include <functional> #include <string> using namespace std ;void test01 () { vector <int >v; v.push_back(10 ); v.push_back(10 ); v.push_back(40 ); v.push_back(20 ); v.push_back(30 ); int num = count(v.begin(), v.end(), 10 ); cout << num << endl ; } class Person { public : Person(string name, int age) { this ->m_Age = age; this ->m_Name = name; } 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 ("s1" ,11 ) ; Person p2 ("s2" ,12 ) ; Person p3 ("s3" ,13 ) ; Person p4 ("s4" ,14 ) ; Person p5 ("s5" ,14 ) ; v.push_back(p1); v.push_back(p2); v.push_back(p3); v.push_back(p4); v.push_back(p5); int num = count(v.begin(), v.end(), p5); cout << num << endl ; } int main (void ) { test01(); test02(); system("pause" ); return 0 ; }
总结 :
统计自定义数据类型时候,需要配合重载operator==
count_if 功能描述 : 按条件统计元素个数。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 #include <iostream> #include <vector> #include <algorithm> #include <functional> using namespace std ;class Greater20 { public : bool operator () (int val) { return val > 20 ; } }; void test01 () { vector <int >v; v.push_back(10 ); v.push_back(20 ); v.push_back(40 ); v.push_back(30 ); v.push_back(50 ); int num = count_if(v.begin(), v.end(), Greater20()); cout << num << endl ; } class Person { public : Person(string name, int age) { this ->m_Age = age; this ->m_Name = name; } string m_Name; int m_Age; }; class AgeGreater20 { public : bool operator () (const Person& p) { return p.m_Age > 20 ; } }; void test02 () { vector <Person>v; Person p1 ("s1" ,11 ) ; Person p2 ("s2" ,22 ) ; Person p3 ("s3" ,33 ) ; Person p4 ("s4" ,44 ) ; v.push_back(p1); v.push_back(p2); v.push_back(p3); v.push_back(p4); int num = count_if(v.begin(), v.end(),AgeGreater20()); cout << num << endl ; } int main (void ) { test01(); test02(); system("pause" ); return 0 ; }
常用的排序算法 学习目标 : 掌握常用的排序算法。
算法简介 :
sort 功能描述 :
对容器内元素进行排序。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #include <iostream> #include <vector> #include <algorithm> #include <functional> using namespace std ;void myPrint (int val) { cout << val << " " ; } void test01 () { vector <int >v; v.push_back(20 ); v.push_back(10 ); v.push_back(60 ); v.push_back(5 ); v.push_back(30 ); v.push_back(2 ); sort(v.begin(), v.end()); for_each(v.begin(), v.end(), myPrint); cout << endl ; sort(v.begin(), v.end(), greater<int >()); for_each(v.begin(), v.end(), myPrint); cout << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : sort属于开发中最常用的算法之一,需熟练掌握。
random_shuffle 功能描述 : 洗牌 指定范围内的元素随机调整次序。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 #include <iostream> #include <vector> #include <algorithm> #include <functional> #include <ctime> using namespace std ;void myPrint (int val) { cout << val << " " ; } void test01 () { vector <int >v; for (int i = 0 ; i < 10 ; i++) { v.push_back(i); } for_each(v.begin(), v.end(),myPrint); cout << endl ; random_shuffle(v.begin(), v.end()); for_each(v.begin(), v.end(), myPrint); cout << endl ; } int main (void ) { srand((unsigned int )time(NULL )); test01(); system("pause" ); return 0 ; }
总结 : random_shuffle洗牌算法比较使用,使用时记得加随机数种子。
merge 功能描述 : 两个容器元素合并,并存储到另一个容器中。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 #include <iostream> #include <vector> #include <algorithm> #include <functional> using namespace std ;void myPrint (int val) { cout << val << " " ; } void test01 () { vector <int >v1; vector <int >v2; for (int i = 0 ; i < 5 ; i++) { v1.push_back(i); v2.push_back(i+5 ); } 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 << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
merge合并的两个容器必须得是有序序列。
reverse 功能描述 : 将容器内元素进行反转。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 #include <iostream> #include <vector> #include <algorithm> #include <functional> using namespace std ;void myPrint (int val) { cout << val << " " ; } void test01 () { vector <int >v; v.push_back(20 ); v.push_back(10 ); v.push_back(60 ); v.push_back(5 ); v.push_back(30 ); v.push_back(2 ); for_each(v.begin(), v.end(), myPrint); cout << endl ; reverse(v.begin(), v.end()); for_each(v.begin(), v.end(), myPrint); cout << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : reverse反转区间内元素,面试题可能涉及到。
常用的拷贝和替换算法 学习目标 :
掌握常用的拷贝和替换算法。
算法简介 :
copy 功能描述 :
容器内指定范围的元素拷贝到另一容器中。
函数原型 “
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 #include <iostream> #include <vector> #include <algorithm> #include <functional> using namespace std ;void myPrint (int val) { cout << val << " " ; } void test01 () { vector <int >v1; for (int i = 0 ; i < 10 ; i++) { v1.push_back(i); } vector <int >v2; v2.resize(v1.size()); copy(v1.begin(), v1.end(), v2.begin()); for_each(v2.begin(), v2.end(), myPrint); cout << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : 利用copy算法在拷贝时,目标容器记得提前开辟空间。
replace 功能描述 : 将容器内指定范围的旧元素修改为新元素。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 #include <iostream> #include <vector> #include <algorithm> #include <functional> using namespace std ;void myPrint (int val) { cout << val << " " ; } void test01 () { vector <int >v; v.push_back(20 ); v.push_back(10 ); v.push_back(60 ); v.push_back(50 ); v.push_back(30 ); v.push_back(20 ); cout << "替换前" << endl ; for_each(v.begin(), v.end(), myPrint); cout << endl ; cout << "替换后" << endl ; replace(v.begin(), v.end(), 20 , 2000 ); for_each(v.begin(), v.end(), myPrint); cout << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : replace会替换区间内满足条件的所有元素。
replace_if 功能描述 : 将区间内满足条件的元素,替换成指定元素。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <iostream> #include <vector> #include <algorithm> #include <functional> using namespace std ;void myPrint (int val) { cout << val << " " ; } class Great30 { public : bool operator () (int val) { return val > 30 ; } }; void test01 () { vector <int >v; v.push_back(20 ); v.push_back(10 ); v.push_back(60 ); v.push_back(50 ); v.push_back(30 ); v.push_back(20 ); cout << "替换前" << endl ; for_each(v.begin(), v.end(), myPrint); cout << endl ; cout << "替换后" << endl ; replace_if(v.begin(), v.end(),Great30(),3000 ); for_each(v.begin(), v.end(), myPrint); cout << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : replace_if按条件查找,可以利用仿函数灵活筛选满足的条件。
swap 功能描述 :互换两个容器的元素。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #include <iostream> #include <algorithm> #include <string> #include <functional> #include <vector> using namespace std ;void MyPrint (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 << "交换前" << endl ; for_each(v1.begin(), v1.end(), MyPrint); cout << endl ; for_each(v2.begin(), v2.end(), MyPrint); cout << endl ; cout << "交换后" << endl ; swap(v1, v2); for_each(v1.begin(), v1.end(), MyPrint); cout << endl ; for_each(v2.begin(), v2.end(), MyPrint); cout << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : swap交换容器时,注意交换的容器是同种类型。
常用算数生成算法 学习目标 : 掌握常用的算数生成算法。
注意 : 算数生成算法属于小型算法,使用时包含的头文件为#include< numeric >
算法简介 :
accumulate 功能描述 : 计算区间内容器元素累计总和。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <iostream> #include <vector> #include <numeric> using namespace std ;void MyPrint (int val) { cout << val << " " ; } void test01 () { vector <int >v; for (int i = 0 ; i <= 100 ; i++) { v.push_back(i); } int total = accumulate(v.begin(), v.end(), 0 ); cout << total << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 : accumulate使用时头文件注意是numeric,这个算法很实用。
fill 功能描述 :
向容器中填充指定的元素。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 #include <iostream> #include <algorithm> #include <numeric> #include <vector> #include <algorithm> using namespace std ;void MyPrint (int val) { cout << val << " " ; } void test01 () { vector <int >v; v.resize(10 ); fill(v.begin(),v.end(),100 ); for_each(v.begin(), v.end(), MyPrint); cout << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :利用fill可以将容器区间内元素填充为指定的值。
常用集合算法 学习目标 :
掌握常用的集合算法。
算法简介 :
set_intersection 功能描述 : 求两个容器的交集。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 #include <iostream> #include <algorithm> #include <string> #include <functional> #include <vector> #include <algorithm> using namespace std ;void MyPrint (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+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 << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
求交集的两个容器必须得是有序序列。
目标容器开辟空间需要从两个容器中取小值。
set_intersection返回值(迭代器)是交集中最后一个元素的位置。
set_union 功能描述 : 求两个集合的并集。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 #include <iostream> #include <algorithm> #include <vector> using namespace std ;void MyPrint (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+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 << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
求并集的两个集合必须得是有序序列。
目标容器开辟空间需要两个容器相加。
set_union返回值(迭代器)是并集中最后一个元素的位置。
set_difference 功能描述 : 求两个集合的差集。
函数原型 :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 #include <iostream> #include <algorithm> #include <vector> using namespace std ;void MyPrint (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+5 ); } vector <int >vTarget; vTarget.resize(max(v1.size(), v2.size())); cout << "v1和v2的差集" << endl ; vector <int >::iterator itEnd = set_difference(v1.begin(), v1.end(), v2.begin(), v2.end(), vTarget.begin()); for_each(vTarget.begin(),itEnd, MyPrint); cout << endl ; cout << "v2和v1的差集" << endl ; itEnd = set_difference(v2.begin(), v2.end(), v1.begin(), v1.end(), vTarget.begin()); for_each(vTarget.begin(), itEnd, MyPrint); cout << endl ; } int main (void ) { test01(); system("pause" ); return 0 ; }
总结 :
求差集的两个集合必须得是有序序列。
目标容器开辟空间需要从两个容器取较大值。