C++提高编程
本阶段主要针对C++泛型编程 和STL 技术做详细讲解
模版
C++另一种编程思想称为泛型编程,主要利用的技术就是模版
C++提供两种模版机制:函数模版 和类模版
函数模板
建立一个通用函数,可以不指定函数返回值类型和参数类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 #include <iostream> using namespace std;template <typename T> void myswap (T& a, T&b) { T temp; temp = a; a = b; b = temp; }int main () { int a = 1 , b = 2 ; char c = 'c' , d = 'd' ; myswap (a, b); myswap (c, d); 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 #include <iostream> using namespace std;template <class T>void my_Sort (T array[], int len) { for (int i = 0 ; i < len; i ++ ) { int max = i; for (int j = i + 1 ; j < len; j ++ ) { if (array[i] < array[j]) { max = j; } } swap (array[i], array[max]); } }int main () { char array[] = "abcdef" ; my_Sort (array, 6 ); for (int i = 0 ; i < 6 ; i ++ ) cout << array[i]; int newarray[] = {1 , 2 , 3 }; my_Sort (newarray, 3 ); for (int i = 0 ; i < 3 ; i ++ ) cout << newarray[i]; }
普通函数与函数模板区别
1 2 3 4 5 6 int myAdd (int a, int b) { return a + b; }int a = 10 ;char b = 'c' ;myAdd (a, b);
1 2 3 4 5 6 7 template <class T>T myAdd (T a, T b) { return a + b; }int a = 10 ;char b = 'c' ;myAdd (a, b);
和普通函数调用类似
普通函数和函数模板的调用规则
如果函数模板和普通函数都可以实现,优先调用普通函数
可以通过空模板参数列表来强制调用函数模板
函数模板也可以发生重载
如果函数模板可以产生更好的匹配优先调用函数模板
模板的局限性
略
学习模板并不是为了写模板,而时在STL中使用系统提供的模板
类模板
1 2 3 4 5 6 7 8 9 10 11 template <class NameType , class AgeType >class Person { NameType a; AgeType b; Person (NameType name, AgeType age) { a = name; b = age; } };Person<string, int > p1 ("libai" , 10 ) ;
类模板与函数模板区别
类模板没有自动类型推导的使用方式
类模板在模板参数列表中可以有默认参数
类模板中成员函数创建时机
类模板对象做函数参数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 template <class T1 , class T2 >class Person {public : T1 name; T2 age; Person (T1 name, T2 age) { this ->name = name; this ->age = age; } void showInfo () { cout << this ->name << " " << this ->age; } };void printPerson (Person<string, int >& p) { p.showInfo (); }void test01 () { Person<string, int > p ("libai" , 1 ) ; printPerson (p); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 template <class T1 , class T2 >class Person {public : T1 name; T2 age; Person (T1 name, T2 age) { this ->name = name; this ->age = age; } void showInfo () { cout << this ->name << " " << this ->age; } };template <class T1, class T2>void printPerson (Person<T1, T2>& p) { p.showInfo (); }void test02 () { Person<string, int > p ("wukong" , 2 ) ; printPerson (p); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 template <class T1 , class T2 >class Person {public : T1 name; T2 age; Person (T1 name, T2 age) { this ->name = name; this ->age = age; } void showInfo () { cout << this ->name << " " << this ->age; } };template <class T>void printPerson (T& p) { p.showInfo (); }void test02 () { Person<string, int > p ("xixi" , 3 ) ; printPerson (p); }
类模板与继承
当子类继承的父类是一个类模板时,子类在声明时,要指定类型
1 2 3 4 5 6 7 8 template <class T >class Base { T m; }class son : public Base<int > { }
1 2 3 4 5 6 7 8 9 10 11 template <class T >class Base { T m; }template <class T1 , class T2 >class son : public Base<T2> { T1 obj; } son<int , char > s;
类模版的分文件编写
类模版中的成员函数只有在调用时才会创建
分文件编写会导致函数内容链接不到
解决方法:
直接包含.cpp文件
将.h和.cpp中的内容写到一起,将后缀名改为.hpp文件
类模版与友元
类外函数访问不到私有变量
STL初识 String
1 2 string str = "hello world" ;int pos = str.find ("hello" );
1 2 3 string s1 = "hello" ; string s2 = "hello" ; str1. compare (s2); 返回0
1 2 3 string s = "hello" ; s.insert (1 , "111" ); s.erase (pos, 3 );
1 2 string str = "abcde" ; string subStr = str.substr (1 , 3 );
Vector
1 2 3 vector<int > v;vector<int > v (n, 10 ) ;vector<int > v1 (v.begin(), v.end())
1 2 vector<int > v (10 , 1 ) ; v.resize (100 );
1 2 v.insert (v.begin (), 1 ); v.erase (v.begin ());
1 2 3 4 5 6 7 8 vector<int > v1 (3 , 1 ) ;vector<int > v2 (3 , 2 ) ; v1. swap (v2); vector<int > v (10000 , 1 ) ; v.resize (10 );vector <int >(v).swap (v);
reserve(int len); // 预留一部分空间,但是size不变
1 2 vector<int > v; v.reserve (1000 );
Deque 双端数组
vector对于头部的插入删除效率低
vector访问元素的速度会比deque快
利用一个中控器
deque.empty()
deque.size()
deque.resize(n)
deque.resize(n, number)
1 2 3 4 5 6 7 8 deque<int > dq; dq.push_back (1 ); dq.push_front (2 ); dq.pop_back (); dq.pop_front (); dq.insert (dq.begin (), 1 ); dq.insert (dq.begin (), newdq.begin (), newdq.end ());
Stack
Queue List
链表:将数据进行链式存储
STL中的链表是一个双向循环链表
链表的迭代器是一个双向迭代器,不支持随机访问
构造函数
1 2 3 4 5 6 7 8 list<int > l1; l1. push_back (1 );list<int > l2 (l1,begin(), l1. end()) ;list<int > l3 (l2) ;list<int > l4 (10 , 100 ) ;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 list<int > l1; l1. push_back (1 ); list<int > l2; l2 = l1; list<int > l3; l3. assign (l2. begin (), l2. end ()); list<int > l4; l4. assign (10 , 100 ); list<int > l1; l1. push_back (1 ); list<int > l2; l2. assign (10 , 100 ); l1. swap (l2);
1 2 3 4 5 6 list<int > l1; l1. push_back (1 ); l1. empty (); l1. resize (10 );
1 2 3 4 5 6 7 8 9 list<int > l1; l1. push_back (1 ); l1. push_front (2 ); l1. pop_back (); l1. pop_front (); l1. insert (l1. begin (), 100 ); l1. erase (l1. begin ()); l1. remove (1000 ); l1. clear ();
list是链表,不是用连续线性空间存储数据,迭代器不支持随机访问,所以不能用[]的方式访问
1 2 3 4 list<int > l1; l1. push_back (1 ); l1.f ront(); l1. back ();
1 2 3 4 list<int > l1; l1. push_back (1 ); l1. reverse (); l1. sort ();
Set
set属于关联式容器,底层结构是用二叉树实现(红黑树)
set不允许容器中有重复的元素
multiset允许容器中有重复元素
set容器在插入数据后会自动排序
1 2 set<int > a; a.insert (1 );
利用仿函数来实现对set的排序
1 2 3 4 5 6 7 8 class campare {public : bool operator () (int v1, int v2) { return v1 > v2; } }; set<int , campare> s; s.insert (1 );
Pair
1 2 pair<char , int > a ('c' , 1 ) ; pair<char , int > a = make_pair (c, 2 );
Map
map中所有元素都是pair
key和value,key是索引
插入删除
1 2 3 4 5 6 map<int , int > a; a.insert (make_pair (1 , 1 )); a.insert (pair <int , int >(2 , 2 )); a.earse (a.begin ()); a.erase (1 );
1 2 map<int , int > a;auto it = a.find (1 );
其它 函数对象
重载函数调用操作符的类,其对象称为函数对象
函数对象使用重载的()时,行为类似函数调用,也叫仿函数
函数对象使用时,可以像普通函数那样调用,可以有参数,可以有返回值
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Myadd {public : int operator () (int a, int b) { return a + b; } };void test01 () { Myadd a; cout << a (10 , 10 ) << endl; }int main () { test01 (); }
函数对象超出了普通函数的概念,函数对象可以有自己的状态
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Myprint {public : Myprint () { this ->count = 0 ; } void operator () (string s) { cout << s << endl; this ->count ++; } int count; };void test02 () { Myprint s; s ("hello world" ); s ("hello world" ); cout << s.count; }int main () { test02 (); }
函数对象可以作为参数进行传递
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Myprint {public : Myprint () { this ->count = 0 ; } void operator () (string s) { cout << s << endl; this ->count ++; } int count; };void doPrint (Myprint& mp, string test) { mp (test); }void test03 () { Myprint s; doPrint (s, "hello world" ); }int main () { test03 (); }
谓词
一元谓词
返回bool类型的仿函数称为谓词
如果operator()接受一个参数,称为一元谓词
如果接受两个参数,称为二元谓词
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class GreatFive {public : bool operator () (int a) { return a > 5 ; } };void test01 () { vector<int > a; a.push_back (1 ); a.push_back (2 ); a.push_back (7 ); vector<int >::iterator it = find_if (a.begin (), a.end (), GreatFive ()); }
二元谓词
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Mycompare {public : bool operatoe () (int a, int b) { return a > b; } }void test01 () { vector<int > v; v.push_back (1 ); v.push_back (3 ); v.push_back (-2 ); sort (v.begin (), v.end (), Mycompare ()); }
内建函数对象
算数仿函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 void test01 () { negate<int > n; cout << n (50 ); }void test02 () { plus<int > a; cout << a (10 , 10 ); }int main () { test01 (); test02 (); }
关系仿函数
1 2 3 4 5 6 7 8 9 void test01 () { vector<int > a; a.push_back (1 ); a.push_back (3 ); a.push_bacl (-1 ); sort (a.begin (), a.end ()); sort (a.begin (), a.end (), greater <int >()); }
逻辑仿函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 void test01 () { vector<bool > v; v.push_back (false ); v.push_back (true ); for (int i = 0 ; i < v.size (); i ++ ) { cout << v[i] << ' ' ; } vector<bool > temp (v.size()) ; transform (v.begin (), v.end (), temp.begin (), logical_not <bool >()) for (int i = 0 ; i < temp.size (); i ++ ) { cout << temp[i] << ' ' ; } }
STL常见算法 是STL头文件中最大的一个,范围涉及到比较、交换、查找、遍历操作、复制、修改
体积很小,只包括几个在序列上面进行简单数学运算的模版函数
定义了一些模版类,用于声明函数对象
遍历算法
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 #include <iostream> #include <bits/stdc++.h> using namespace std;class print {public : void operator () (int val) { cout << val << endl; } };void print01 (int val) { cout << val << ' ' ; }void test01 () { vector<int > v; v.push_back (1 ); v.push_back (3 ); for_each(v.begin (), v.end (), print ()); } int main () { test01 (); }
transform
将一个容器的内容搬运到另一个容器
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 <bits/stdc++.h> using namespace std;class Trans {public : int operator () (int v) { return v + 1 ; } };class print {public : void operator () (int val) { cout << val << ' ' ; } };void test01 () { vector<int > v; v.push_back (17 ); v.push_back (1 ); vector<int > target; target.resize (v.size ()); transform (v.begin (), v.end (), target.begin (), Trans ()); for_each(target.begin (), target.end (), print ()); } int main () { test01 (); }
查找算法
find
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 #include <iostream> #include <bits/stdc++.h> using namespace std;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 << *it; } int main () { test01 (); }
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 <bits/stdc++.h> using namespace std;class Person {public : string name; int age; Person (string name, int age) { this ->age = age; this ->name = name; } bool operator ==(const Person& p) { if (this ->name == p.name && this ->age == p.age) return true ; else return false ; } };void test01 () { Person p1 = Person ("libai" , 1 ); Person p2 = Person ("wangwei" , 2 ); Person p3 = Person ("dufu" , 3 ); vector<Person> v; v.push_back (p1); v.push_back (p2); v.push_back (p3); vector<Person>::iterator it = find (v.begin (), v.end (), p2); if (it != v.end ()) cout << (*it).name << ' ' << (*it).age; } int main () { test01 (); }
find_if
1 2 3 4 5 6 7 8 9 10 11 12 13 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); auto it = find_if (v.begin (), v.end (), greaterFive ()); if (it != v.end ()) cout << *it; }
adjacent_find
查找相邻重复元素
返回相邻元素的第一个元素的迭代器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 #include <iostream> #include <bits/stdc++.h> using namespace std;void test02 () { vector<int > v; for (int i = 0 ; i < 5 ; i ++ ) v.push_back (i); v.push_back (4 ); auto it = adjacent_find (v.begin (), v.end ()); if (it != v.end ()) cout << *it << ' ' << *(it ++); }int main () { test02 (); }
binary_search
查找指定元素是否存在,查到了返回True,否则返回false
1 2 3 4 5 6 7 8 9 10 void test01 () { vector<int > v; for (int i = 0 ; i < 10 ; i = i + 2 ) v.push_back (i); bool ans = binary_search (v.begin (), v.end (), 5 ); cout << ans; }
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 void test01 () { vector<int > v; for (int i = 0 ; i < 10 ; i ++ ) v.push_back (i); int num = count (v.begin (), v.end (), 1 );s cout << num; }class Person {public : int age; string name; bool operator ==(const Person& p) { if (this ->age == p.age) return true ; else return false ; } Person (string name, int age) { this ->name = name; this ->age = age; } };void test02 () { vector<Person> p; Person p1 ("libai" , 1 ) ; Person p2 ("zhangsan" , 1 ) ; p.push_back (p1); p.push_back (p2); int num = count (p.begin (), p.end (), p2); }
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 #include <iostream> #include <bits/stdc++.h> 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); int num = count_if (v.begin (), v.end (), greaterFive ()); cout << num; }void test02 () { }int main () { test01 (); }
排序算法
sort
sort(iterator beg, iterator end, _Pred); // _Pred是谓词
1 2 3 4 5 6 7 8 9 void test01 () { vector<int > v; v.push_back (9 ); v.push_back (-2 ); v.push_back (7 ); sort (v.begin (), v.end ()); }
random_shuffle
打乱数据,洗牌
1 2 3 4 5 6 7 void test01 () { vector<int > v; for (int i = 0 ; i < 10 ; i ++ ) v.push_back (i); random_shuffle (v.begin (), v.end ()); }
merge
两个有序容器元素合并
1 2 3 4 5 6 7 8 9 void test01 () { vector<int > v1 = {1 , 2 , 3 }; vector<int > v2 = {4 , 7 , 9 }; vector<int > v; v.resize (v1. size () + v2. size ()); merge (v1. begin (), v1. end (), v2. begin (), v2. end (), v.begin ()); }
reverse
反转元素
拷贝和替换算法
copy
1 2 3 4 5 6 7 void test01 () { vector<int > v1 = {1 , 2 , 3 }; vector<int > v; v.resize (v1. size ()); copy (v1. begin (), v1. end (), v.begin ()); }
replace
replace(iterator beg, iterator end, old_val, new_val)
1 2 3 4 5 void test01 () { vector<int > v1 (3 , 10 ) ; replace (v1. begin (), v1. end (), 10 , 20 ); }
replace_if
replace(iterator beg, iterator end, _Pred, new_val)
1 2 3 4 5 6 7 8 9 10 11 12 13 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); replace_if (v.begin (), v.end (), greaterFive (), 2000 ); }
swap
互换两个容器的元素
1 2 3 4 5 6 7 8 9 10 void test01 () { vector<int > v1 = vector <int >(5 , 1 ); vector<int > v2 = vector <int >(6 , 7 ); swap (v1, v2); for (int i = 0 ; i < v1. size (); i ++ ) cout << v1[i] << ' ' ; cout << endl; for (int i = 0 ; i < v1. size (); i ++ ) cout << v2[i] << ' ' ; }
算术生成算法
accumulate
1 2 3 4 5 6 7 8 9 void test01 () { vector<int > v; for (int i = 0 ; i <= 100 ; i ++ ) v.push_back (i); int num = accumulate (v.begin (), v.end (), 0 ); cout << num; }
fill
向容器中填充指定元素
1 2 3 4 5 6 void test01 () { vector<int > v; v.resize (10 ); fill (v.begin (), v.end (), 100 ); }
常见集合算法
set_intersection
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 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 > target; target.resize (min (v1. size (), v2. size ())); auto it = set_intersection (v1. begin (), v1. end (), v2. begin (), v2. end (), target.begin ()); }
set_union
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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 > target; target.resize (v1. size () + v2. size ()); auto it = set_union (v1. begin (), v1. end (), v2. begin (), v2. end (), target.begin ()); }
set_difference
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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 > target; target.resize (max (v1. size (), v2. size ())); auto it = set_difference (v1. begin (), v1. end (), v2. begin (), v2. end (), target.begin ()); }