作业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类,以及这个拼写是奇怪的……

posted @ 2020-04-01 22:44  timeaftertime  阅读(274)  评论(0编辑  收藏  举报