一,day1-day7:
1. 可以直接比较string对象的大小,而c风格字符串比较的只是指针大小
例子1:
string a[] = { "ab", "cd" };
if( a[1] > a[0] ){ cout << "yes" } //将输出yes
const char *ch[] = { "good", "test", "nihao" };
ch[0] > ch[1] // 这里比较的只是指针大小,而不是比较字符串的大小
例子2:
template <class V> bool lessthan( const V &lh, const V &rh ) { return lh < rh; } bool lessthan( const char* &lh, const char* &rh ) { return strcmp( lh, rh ) < 0; } template <class T > void sort( T a[], int len ) { for( int i = 0; i < len - 1; i++ ) { for( int j = i + 1; j < len; j++ ) { if( lessthan( a[i], a[j] ) // 实例化lessthan函数时如果已经有对应的函数,则不会再实例化模板了 { swap( a[i], a[j] ); } } } } template <class T> void display( T a[], int len ) { for( int i = 0; i < len; i++ ) { cout << a[i] << " "; } } string d[] = { "cd", "ab", "kn", "gk" }; const char *ch = { "good", "morning", "nice", "to" }; sort( d, 4 ); display( d, 4 ); //可以对string数组进行排序 sort( d, 4 ); // 此时也可以对c风格字符串进行排序了注:编译器会优先选择最匹配的特殊化版本来使用,在没有更匹配的特殊化版本才选用
#include <iostream> #include <string> #include <typeinfo> using namespace std; template <class V> bool lessthan( const V &lh, const V &rh )// 模板1 { return lh > rh; } template <> // 对C风格字符串常量的特殊化,为全特化,相当于V对应于const char*,此为模板,不调用时不产生代码,而函数则会有代码 bool lessthan( const char *const &lh, const char *const &rh ) // 模板2,都要写const,要与上面那个模板lessthan保持一致(上面模板1参数为const类型,所以这里也要在参数前加const),即在一致的情况下更加具体,才会实例化该具体模板 { return strcmp( lh, rh ) > 0; } /*或者下面的也行: template <class V> bool lessthan( V &lh, V &rh ) { return lh > rh; } template <> // 对C风格字符串常量的特殊化,为全特化,相当于V对应于const char*,此为模板,不调用时不产生代码,而函数则会有代码 bool lessthan( const char * &lh, const char * &rh ) // 都要写const,要与上面那个模板lessthan保持一致(上面模板1参数为const类型,所以这里也要在参数前加const),即在一致的情况下更加具体,才会实例化该具体模板 { return strcmp( lh, rh ) > 0; } 注:模板重载,一个更加具体的模板必须在与另一个模板保持一致的情况下更加具体,例如上面的模板2在与模板1保持一致的情况下 更加具体,模板1实例化const char*时V要实例化为char*,而模板2则直接用 */ template <class T > void sort( T a[], int len ) { for( int i = 0; i < len - 1; i++ ) { for( int j = i + 1; j < len; j++ ) { if( lessthan( a[i], a[j] ) ) { swap( a[i], a[j] ); } } } } template <class T> void display( T a[], int len ) { for( int i = 0; i < len; i++ ) { cout << a[i] << " "; } cout << endl; } int main() { int a[] = { 2, 3, 1, 6, 5, 4 }; char b[] = { 'a', 'n', 'c' }; double c[] = { 2.3, 1.4, 4.2, 3.3 }; string d[] = { "cd", "ab", "kn", "gk" }; const char* ch[] = { "nice", "to", "meet", "you" }; sort( a, 6 ); display( a, 6 ); sort( b, 3 ); display( b, 3 ); sort( c, 4 ); display( c, 4 ); sort( d, 4 ); display( d, 4 ); sort( ch, 4 ); display( ch, 4 ); // cout << endl << typeid(const char*).name() << endl; system("pause"); return 0; }
#include <iostream> using namespace std; template <class T> void print( const T &d ) { cout << d << ' '; return; } template < class T, int N > void print( T(&a)[N] ) // 用于数组的特殊化版本,可以传递一维或多维数组,在此为偏特化 { for( int i = 0; i < N; i++ ) { print(a[i]); } return; } int main() { int arry[] = { 2, 3, 4 }; int b[3][2] = { 11, 22, 33, 44, 55, 66 }; print(arry); // 输出2 3 4 cout << endl; print(b); // 输出11 22 33 44 55 66 system("pause"); return 0; }
#include <iostream> using namespace std; template <typename T> void print( const T &d ) { cout << d << ' '; return; } template <typename T> void print( T *p ) { cout << *p << endl; return; } template < class T, int N > // 模板1 void print( T(&a)[N] ) // 用于数组的特殊化版本,可以传递一维或多维数组,在此为偏特化 { for( int i = 0; i < N; i++ ) { print(a[i]); } return; } template <> // C风格字符串的特殊化,在此为全特化 // 模板2 void print( const char *s ) { cout << s; return; } int main() { print("hello"); // vs2010,则出错:“print”: 对重载函数的调用不明确,其不知道实例化模板1还是模板2 system("pause"); return 0; }
#include <iostream> using namespace std; template <typename K, typename V> struct Pair { K first; V second; void show(){ cout << first << ' ' << second << endl; } }; template <typename K, typename V> Pair<K, V> makepair( K x, V y ) { Pair<K, V> pkv = { x, y }; return pkv; } int main() { makepair( 1, "hello" ).show(); // 根据数据产生pair system("pause"); return 0; }注:特殊化有几种层次
#include <iostream> #include <string> using namespace std; template <class K, class V> struct Pair { K first; V second; public: Pair():first(), second(){} template <class F, class Q> // 成员函数模板 Pair( const F &x, const Q &y ):first(x), second(y){} template <typename I, typename J> // 为了保证不同Pair实例化对象之间的赋值,要为模板,如Pair<int,double>类型赋值给Pair<char, double>类型 Pair& operator=( const Pair<I, J> &value ) { first = value.first; second = value.second; return *this; } void show() { cout << first << ' ' << second << endl; return; } friend ostream& operator<<( ostream &os, const Pair &v ) { return os << v.first << ' ' << v.second << endl; } }; int main() { Pair<int, double> pid1( 1, 2.3 ); // 'a'不是int类型,2不是double类型,但可以转换为对应的类型 Pair<char, int> pid2( 'a', 30 ); // 这里传的数据并不一定是对应的int 和double类型,所以上面的构造函数要为模板成员函数 //pid1.show(); cout << pid1; pid1 = pid2; // 若没有上面定义的赋值模板,则该语句编译不过 //pid1.show(); cout << pid1; char a[10] = "aa"; char b[10] = "oo"; Pair<const char*, const char*> pcc(a, b ); // pcc对象中存的是两个地址 Pair<string, string> pss;// 保存的是字符串 pss = pcc; // pss会把pcc中的数据保存一份 cout << pss; // 输出aa oo cout << pcc; strcpy( a, "cc" ); strcpy( b, "pp" ); cout << "\nafter copy\n"; cout << pcc; // 输出cc pp cout << pss; // 输出aa oo system("pause"); return 0; }
#include <iostream> using namespace std; template < typename T, int N > class Array { private: T a[N]; public: T& operator[]( int index ) // 函数1 const的Array对象可以调用此函数,也可以调用下面的函数2 { return a[index]; } const T& operator[]( int index )const // 函数2,对应const的Array对象只能调用该函数,因为只有const函数能保证不修改对象 { return a[index]; } void fill( T start, const T &step ) { for( int i = 0; i < N; i++, start += step ) { a[i] = start; } return; } template <typename A, int M > //友元函数模板 friend ostream& operator<<( ostream &o, const Array<A, M> &x ); // 尽量不要将声明与定义分开写 }; template < typename A, int M > // 在外面定义友元函数模板 ostream& operator<<( ostream &o, const Array<A, M> &x ) { o << "[ "; for( int i = 0; i < M; i++ ) { o << x[i] << ' '; // const的x对象将调用函数2 } o << "] "; return o; } int main() { Array< int, 5 > a1; a1.fill( 11, 2 ); cout << a1 << endl; // 输出[ 11 13 15 17 19 ] system("pause"); return 0; }/*
#include <iostream> #include <string> using namespace std; typedef struct Date { int year; int month; int day; friend ostream& operator<<( ostream &os, const Date& d ) { return os << d.year << '-' << d.month << '-' << d.day; } }Date; template < typename V > bool isEqual( const V left, const V right ) // 模板1 { if( left == right ) { return true; } return false; } template <> bool isEqual( const char* left, const char* right ) // 模板2,模板2与模板1构成模板重载 { if( strcmp( left, right ) == 0 ) { return true; } return false; } template <> bool isEqual( Date left, Date right ) // 模板2,模板2与模板1构成模板重载 { if( left.month == right.month && left.year == right.year && left.day == right.day ) { return true; } return false; } template < typename T > T* find( T a[], int len, T value ) // 模板1 { for( int i = 0; i < len; i++ ) { if( isEqual( a[i], value ) ) { return &a[i]; } } return NULL; } /* template <> // 这样也可以,针对C风格字符串的特化 const char** find( const char *a[], int n, const char* v )// 模板2,这里特化必须要与模板1对应,且更加具体 { for( int i = 0; i < n; i++ ) { if( strcmp( a[i], v ) == 0 ) { return a + i; } } return NULL; } */ int main() { char ch[] = { 'd', 'e', 'a' }; double d[] = { 1.1, 2.3, 4.4 }; string str[] = { "ad", "ad", "sgg" }; const char* cch[] = { "hello", "nice", "to" }; Date dd[] = { {2010, 1, 1 }, { 2011, 2, 2 }, { 2013, 3, 3 } }; cout << *find( ch, 3, 'e' ) << endl; cout << *find( d, 3, 2.3 ) << endl; string target = "sgg"; cout << *find( str, 3, target ) << endl; const char** pcc = find( cch, 3, "to" ); cout << *pcc << endl; Date d1 = { 2011, 2, 2 }; cout << *find( dd, 3, d1 ) << endl; system("pause"); return 0; }
iterator,const_iterator,reverse_iterator,const_reverse_iterator
2. 容器会自己保存一份数据,因此自定义类型的数据要保存在容器中,应该支持拷贝构造和赋值运算符以及无参构造
int a[] = { 2, 3, 4, 5, 6, 1, 8, 9 };
sort( a, a + 8 );
cout << endl;
list<int> lt( a, a + 8 ); //lt自己会保存一份数据
3. 插入数据时,可能会释放空间,所以原来的迭代器在插入或删除数据之后很可能失效了,应该重新取得迭代器。
它是随机迭代器(可以加上一个整数的),当然也是双向迭代器(可以++和--)。
4. STL和容器
4.1 STL
4.2 标准容器:类模板
序列式容器:vector,deque,list
关联式容器:set数据集,multiset多重数据集,map映射,multimap多重映射
4.3 容器适配器:对容器的再包装,进行了访问限制
stack栈:先进后出
queue队列:先进先出
priority_queue优先队列:最大的先出
4.4 通用算法:约70种