作业8-STL1作业
1.goodcopy
编写GoodCopy类模板,使得程序按指定方式输出
1 #include <iostream> 2 using namespace std; 3 4 template <class T> 5 struct GoodCopy { 6 void operator()(T*s,T*e,T*to) { 7 for( ; e != s; e--){ 8 *(to+(e-s)-1) = *(e-1); //注意e-s要加括号 9 } 10 } 11 }; 12 13 int a[200]; 14 int b[200]; 15 string c[200]; 16 string d[200]; 17 18 template <class T> 19 void Print(T s,T e) { 20 for(; s != e; ++s) 21 cout << * s << ","; 22 cout << endl; 23 } 24 25 int main() 26 { 27 int t; 28 cin >> t; 29 while( t -- ) { 30 int m ; 31 cin >> m; 32 for(int i = 0;i < m; ++i) 33 cin >> a[i]; 34 GoodCopy<int>()(a,a+m,b); //GoodCopy<int>()产生了一个临时对象,通过产生临时对象调用重载运算符 35 Print(b,b+m); 36 GoodCopy<int>()(a,a+m,a+m/2); //从中间开始复制,要防止覆盖 37 Print(a+m/2,a+m/2 + m); 38 39 for(int i = 0;i < m; ++i) 40 cin >> c[i]; 41 GoodCopy<string>()(c,c+m,d); 42 Print(c,c+m); 43 GoodCopy<string>()(c,c+m,c+m/2); 44 Print(c+m/2,c+m/2 + m); 45 } 46 return 0; 47 }
备注:函数对象也叫仿函数。如果一个类将()
运算符重载为成员函数,这个类就称为函数对象类,这个类的对象就是函数对象。函数对象是一个对象,但是使用的形式看起来像函数调用,实际上也执行了函数调用,因而得名。其实就是一个对象,重载了小括号。然后调用的时候有两种方法,一个是GoodCopy<int>a; a(a,a+m,b),这种方法就是要命名一个GoodCopy对象,也可以像这道题里建一个临时对象。还有就是因为有从中间开始复制的情况,所以要倒着复制,要用e--来遍历。
2.按距离排序
1 #include <iostream> 2 #include <cmath> 3 #include <algorithm> 4 #include <string> 5 using namespace std; 6 template <class T1,class T2> 7 struct Closer { 8 // 在此处补充你的代码 9 T1 n; 10 T2 cmp; 11 Closer(T1 n_, T2 cmp_):n(n_),cmp(cmp_){} 12 bool operator()(const T1 & a, const T1 & b){ 13 if(cmp(a,n)==cmp(b,n)) return a<b; 14 return cmp(a,n)<cmp(b,n); 15 } 16 }; //函数对象 17 18 int Distance1(int n1,int n2) { 19 return abs(n1-n2); 20 } 21 int Distance2(const string & s1, const string & s2) 22 { 23 return abs((int)s1.length()- (int) s2.length()); 24 } 25 int a[10] = { 0,3,1,4,7,9,20,8,10,15}; 26 string b[6] = {"American","Jack","To","Peking","abcdefghijklmnop","123456789"}; 27 int main() 28 { 29 int n;string s; 30 while( cin >> n >> s ) {//sort,判断x是否比y靠前,就看cmp(x, y)是否为true 31 sort(a,a+10,Closer<int ,int (*)(int ,int)> (n,Distance1)); //函数指针 32 for(int i = 0;i < 10; ++i) 33 cout << a[i] << "," ; 34 cout << endl; 35 sort(b,b+6,Closer<string,int (*)(const string &,const string & )> (s,Distance2)); 36 for(int i = 0;i < 6; ++i) 37 cout << b[i] << "," ; 38 cout << endl; 39 } 40 return 0; 41 }
备注:Closer<int ,int (*)(int ,int)> (n,Distance1)这是一个对象,int(*)(int ,int)是一个函数指针。sort函数,判断x是否比y靠前,就看cmp(x, y)是否为true .
3.很难蒙混过关的CArray3d三维数组模板类
1 #include <iostream> 2 #include <iomanip> 3 #include <cstring> 4 using namespace std; 5 template <class T> 6 class CArray3D 7 { 8 // 在此处补充你的代码 9 public: //内部类一般是public 10 class CArray2D{ 11 public: 12 int y,z; 13 T * p; 14 void set(int m, int n){ 15 y = m, z = n; 16 p = new T[m*n]; 17 } 18 T * operator[](int k){ 19 return p+k*z; 20 } 21 operator T*(){ //强制转换成指针 22 return this->p; 23 } 24 }; 25 int x; 26 CArray2D * array; 27 CArray3D(int x_, int y_, int z_):x(x_){ 28 array = new CArray2D[x_]; //有参构造函数不能直接用于数组的构造 29 for(int i = 0; i < x_; i++) 30 array[i].set(y_, z_); 31 } 32 CArray2D & operator[](int n){ 33 return array[n]; 34 } 35 }; 36 37 CArray3D<int> a(3,4,5); 38 CArray3D<double> b(3,2,2); 39 void PrintA() 40 { 41 for(int i = 0;i < 3; ++i) { 42 cout << "layer " << i << ":" << endl; 43 for(int j = 0; j < 4; ++j) { 44 for(int k = 0; k < 5; ++k) 45 cout << a[i][j][k] << "," ; 46 cout << endl; 47 } 48 } 49 } 50 void PrintB() 51 { 52 for(int i = 0;i < 3; ++i) { 53 cout << "layer " << i << ":" << endl; 54 for(int j = 0; j < 2; ++j) { 55 for(int k = 0; k < 2; ++k) 56 cout << b[i][j][k] << "," ; 57 cout << endl; 58 } 59 } 60 } 61 62 int main() 63 { 64 65 int No = 0; 66 for( int i = 0; i < 3; ++ i ) { 67 a[i]; 68 for( int j = 0; j < 4; ++j ) { 69 a[j][i]; 70 for( int k = 0; k < 5; ++k ) 71 a[i][j][k] = No ++; 72 a[j][i][i]; 73 } 74 } 75 PrintA(); 76 memset(a[1],-1 ,20*sizeof(int)); 77 memset(a[1],-1 ,20*sizeof(int)); 78 PrintA(); 79 memset(a[1][1],0 ,5*sizeof(int)); 80 PrintA(); 81 82 for( int i = 0; i < 3; ++ i ) 83 for( int j = 0; j < 2; ++j ) 84 for( int k = 0; k < 2; ++k ) 85 b[i][j][k] = 10.0/(i+j+k+1); 86 PrintB(); 87 int n = a[0][1][2]; 88 double f = b[0][1][1]; 89 cout << "****" << endl; 90 cout << n << "," << f << endl; 91 92 return 0; 93 }
备注:这道题要注意看提示:
建议做法:
1. a[i][j][k] 这个表达式的第一个[]返回一个内部类的对象,该内部类也重载了[],且返回值为指针。
2. 必要时需重载对象到指针的强制类型转换运算符
内部类也叫嵌套类https://blog.csdn.net/liyuanbhu/article/details/43897979,详情可以看这里。我本来想试图直接用构造函数直接构造CArray2D * array;但发现必须得些for循环那一行来用set初始化,因为new调用的只能是无参构造函数。
memset里的a[1]需要是一个地址,a[1]本身是一个CArray2D,所以要强制类型转换成指针。
4.函数对象的过滤器
1 #include <iostream> 2 #include <vector> 3 using namespace std; 4 5 struct A { 6 int v; 7 A() { } 8 A(int n):v(n) { }; 9 bool operator<(const A & a) const { 10 return v < a.v; 11 } 12 }; 13 // 在此处补充你的代码 14 template <class T> 15 struct FilterClass{ 16 T m, n; //这里不能是int 17 FilterClass(int mm, int nn):m(mm),n(nn){} //注意数据类型 18 bool operator()(T a){ 19 return (m<a)&&(a<n); //必须是小于号,因为只重载了小于号 20 } 21 }; 22 23 template <class T> 24 void Print(T s,T e) 25 { 26 for(;s!=e; ++s) 27 cout << *s << ","; 28 cout << endl; 29 } 30 template <class T1, class T2,class T3> 31 T2 Filter( T1 s,T1 e, T2 s2, T3 op) 32 { 33 for(;s != e; ++s) { 34 if( op(*s)) { //这个函数的参数就是*s 35 * s2 = * s; 36 ++s2; 37 } 38 } 39 return s2; 40 } 41 42 ostream & operator <<(ostream & o,A & a) 43 { 44 o << a.v; 45 return o; 46 } 47 vector<int> ia; 48 vector<A> aa; 49 int main() 50 { 51 int m,n; 52 while(cin >> m >> n) { 53 ia.clear(); 54 aa.clear(); 55 int k,tmp; 56 cin >> k; 57 for(int i = 0;i < k; ++i) { 58 cin >> tmp; 59 ia.push_back(tmp); 60 aa.push_back(tmp); 61 } 62 vector<int> ib(k); 63 vector<A> ab(k); 64 vector<int>::iterator p = Filter(ia.begin(),ia.end(),ib.begin(),FilterClass<int>(m,n)); //一个临时的函数对象,可以理解成一个函数名 65 Print(ib.begin(),p); 66 vector<A>::iterator pp = Filter(aa.begin(),aa.end(),ab.begin(),FilterClass<A>(m,n)); 67 Print(ab.begin(),pp); 68 69 } 70 return 0; 71 }
备注:两个注意的地方。一个是重载的是小于号,因此只能用小于号来比较A类对象。二是注意FilterClass里的变量类型,需得是T类,不能是int。
5.白给的list排序
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <list> 5 using namespace std; 6 int main() 7 { 8 double a[] = {1.2,3.4,9.8,7.3,2.6}; 9 list<double> lst(a,a+5); 10 lst.sort(//list只能用自己的sort 11 // 在此处补充你的代码 12 greater<int>() 13 ); 14 15 for(list<double>::iterator i = lst.begin(); i != lst.end(); ++i) 16 cout << * i << "," ; 17 return 0; 18 }
list只能用自己的sort来排序,只有两种sort,一种无参一种有参。这里就是填了个sort的参数:greater<int>()这个函数对象
6.我自己的ostream_iterator
1 #include <iostream> 2 #include <list> 3 #include <string> 4 using namespace std; 5 6 template <class T1,class T2> 7 void Copy(T1 s,T1 e, T2 x) 8 { 9 for(; s != e; ++s,++x) 10 *x = *s; 11 } 12 13 14 template<class T> 15 class myostream_iteraotr 16 { 17 // 在此处补充你的代码 18 ostream & out; 19 string s; 20 public: //总是忘记public…… 21 myostream_iteraotr(ostream & out_, string s_):out(out_),s(s_){} 22 void operator++(){} 23 myostream_iteraotr& operator*(){return *this;} //这俩其实都没啥用,但这里一定要返回的是 myostream_iteraotr,因为等于号是作用在*x上的 24 void operator=(T a){ 25 out<<a<<s; 26 } 27 }; 28 29 30 int main() 31 { const int SIZE = 5; 32 int a[SIZE] = {5,21,14,2,3}; 33 double b[SIZE] = { 1.4, 5.56,3.2,98.3,3.3}; 34 list<int> lst(a,a+SIZE); 35 myostream_iteraotr<int> output(cout,","); 36 Copy( lst.begin(),lst.end(),output); 37 cout << endl; 38 myostream_iteraotr<double> output2(cout,"--"); 39 Copy(b,b+SIZE,output2); 40 return 0; 41 }
备注:可以和上一节的istream_iterator对比着看。区别在于++不执行任何操作,=号执行输出,同时要注意*的返回值一定是myostream_iteraotr类,以及这个拼写是奇怪的……