北大C++程序设计编程作业答案+解析·输入输出和模板

本章一共包含七个编程习题:

  1. 简单的SumArray
  2. 简单的foreach
  3. 简单的Filter
  4. 你真的搞清楚为啥 while(cin >> n) 能成立了吗?
  5. 山寨版istream_iterator
  6. 这个模板并不难
  7. 排序,又见排序!

以下习题答案全部通过OJ,使用编译器为:G++(9.3(with c++17))

1. 简单的SumArray

考点:函数模板,指针

解析:本题需要调用SumArray()把两个不同类型的数组的元素,相加在一起,所以我们先来看看它的参数是什么

// 要把array里面的所有元素相加,那么我们需要遍历所有元素一边
// 这里可以把两个参数看成两个元素指针,第一个表示数组第一个元素的起始地址,
// 第二个表示数组的末尾元素地址 + 1,即表示的元素范围为:[ start_ptr, end_ptr ] or [ start_ptr, end_ptr + 1 )
SumArray( array, array + 4 )
// 对于为什么是末尾元素地址 + 1,我们看看下面的长度为5的数组的例子
0x0    0x1     0x2     0x3    0x4     0x5
  a      b       c       d      e
  ^                                    ^
  s                                   s + 5

确定参数类型后,在函数内部,我们只需遍历每一个元素,进行累加操作即可:

// 获取数组第一个元素
T t = *s;

for ( 
    // 跳过第一个元素
    s += 1; 
    // 只要s(数组开始地址)不等于e(数组末尾地址+1),则继续遍历相加
    s != e; 
    // 遍历下一个元素
    s += 1 
) {
    t += *s; // 累加
}

return t;

答案:完整源码地址

// 这里只给到需要补完的代码,完整代码请移步到github
template <class T>
T SumArray( T *s, T *e ) {
    // 在此处补充你的代码
    T t = *s;
    for ( s += 1; s != e; s += 1 ) {
        t += *s;
    }

    return t;
}

2. 简单的foreach

考点:函数模板,函数指针

解析:题目的关键是下面两行代码:

std::string array[ 100 ];
int a[ 100 ];
MyForeach( array, array + m, Print );
MyForeach( a, a + n, Inc );

函数参数的前两个形式,我们已经很熟悉了,还是不熟悉的童鞋可以参考上题:简单的SumArray,那么第三个参数是不同类型的函数指针,所以MyForeach()函数需要两个模板变量,一个表示数组元素类型,另一个表示调用函数的类型,并且根据题意,遍历每个元素时,需要调用函数参数进行处理。另外需要注意,题目调用的函数都是引用或对象,不是指针,所以调用时需要对指针进行取值操作。

答案:完整源码地址

// 这里只给到需要补完的代码,完整代码请移步到github
// 在此处补充你的代码
template<class T, class F>
void MyForeach( T *s, T *e, F *f ) {
    for ( ; s != e; s += 1 ) {
        f( *s ); // 对指针进行取值操作
    }
}

3. 简单的Filter

考点:函数模板,函数指针

解析:思路和上题差不多,唯一需要注意的就是返回值是目标数组的最后一个指针地址 + 1,因为外面遍历的时候,使用了地址运算,求得一共需要遍历多少个元素:

// p是as2最后一个元素地址 + 1,as2又是第一个元素地址,那么p - as2 + 1表示一共有多少个元素
// i < p - as2就是遍历所有元素的下标
for ( int i = 0; i < p - as2; ++i )

答案:完整源码地址

// 这里只给到需要补完的代码,完整代码请移步到github
// 在此处补充你的代码
template<class T, class F>
T *Filter( 
    // 需要filter的数组第一个元素地址
    T *s, 
    // 需要filter的数组最后一个车元素地址 + 1
    T *e, 
    // 目标数组第一个元素地址,这个数组用于存储filter后的结果
    T *R, 
    // filter函数指针
    F *f
) {
    for ( ; s != e; s += 1 ) {
        if ( f( *s ) ) {
            *R = *s;
            R += 1;
        }
    }

    return R;
}

4. 你真的搞清楚为啥 while(cin >> n) 能成立了吗?

考点:类型转换运算符

解析:本题第一需要重载运算符>>,用于cin的输入,这个不难,第二个就是如何实现下面语句:

while ( m >> n1 >> n2 )

这里 m >> n1 >> n2 返回值是MyCin对象是不能当作bool类型使用的,所以我们需要强制转换成bool类型,需要使用到下面语法:

explicit operator bool() const {
    // 返回需要的值,最后强制转换后的bool值
}

因为我们只需要当输入为-1时,结束程序,我们就用一个bool成员变量纪录程序状态,当输入为-1时,设置为false,然后强制转换时返回它就行。

答案:完整源码地址

// 这里只给到需要补完的代码,完整代码请移步到github
class MyCin {
    // 在此处补充你的代码
    bool f = true;

public:
    MyCin &operator>>( int &n ) {
        if ( !f ) return *this;

        std::cin >> n; // Always enter this line.
        if ( n == -1 ) f = false;

        return *this;
    }

    explicit operator bool() const {
        return f;
    }
};

5. 山寨版istream_iterator

考点:类模板

解析:本题需要重载两个运算符:

// 从cin中读取当前的值
n1 = *inputInt;
// 移动iterator指向下一个值
inputInt++;

重载运算符*时,我们只需返回类里面从cin读取的值,重载运算符++时,我们从cin中读取一个新的值,也就是iterator指向了下一个值,通过这种方法来实现我们自己的istream_iterator。

答案:完整源码地址

// 这里只给到需要补完的代码,完整代码请移步到github
template<class T>
class CMyistream_iterator {
    // 在此处补充你的代码
    T v; // 相当于iterator
    std::istream &is; // std::cin

public:
    CMyistream_iterator( std::istream &is_ ) : is( is_ ) { is >> v; }

    T &operator*() {
        return v; // 返回当前值
    }

    CMyistream_iterator<T> operator++( int n ) {
        CMyistream_iterator t = *this;
        // 从cin里面读取下一个值
        is >> v;
        return t;
    }
};

6. 这个模板并不难

考点:类模板

解析:题目要求在输入的每个元素之后,插入一个逗号,那么我们可以在构造函数里面初始化一个数组用于存储输入数据,然后再Show()函数里面进行输出。这里注意需要输出的数组数据类型不一致,所以需要模板来实现。

答案:完整源码地址

// 这里只给到需要补完的代码,完整代码请移步到github
template<class T>
class myclass {
    // 在此处补充你的代码
    T *p;
    size_t size;

public:
    myclass( const T* C_, size_t n_ ) {
        size = n_;
        p = new T[ n_ ];
        std::copy( C_, C_ + n_, p );
    }

    ~myclass() {
        delete[] p;
    }

    void Show() {
        for ( int i = 0; i < size; i++ ) {
            std::cout << p[ i ] << ",";
        }
        std::cout << std::endl;
    }
};

7. 排序,又见排序!

考点:函数模板

解析:题目要求实现一个可以接受任意类型的sort函数,那么我们就需要考虑使用模板进行实现,这里需要有两个模板类型,一个时数组的类型,一个是排序比较函数的类型,题主这里使用了最简单的冒泡排序,所以时间复杂度是O( n )

答案:完整源码地址

// 这里只给到需要补完的代码,完整代码请移步到github
// 在此处补充你的代码
template<class T1, class T2>
void mysort( T1 *s, T1 *e, T2 *f ) {
    // Bubble sort
    // 这里都是用指针进行数组遍历
    for ( ; s != e; s += 1 ) { // 第一层遍历每个元素
        T1 *t = s + 1;
        for ( ; t != e; t += 1 ) { // 第二次遍历,找到当前最大的元素
            if ( !f( *s, *t ) ) { // 交换
                T1 tv = *s;
                *s = *t;
                *t = tv;
            }
        }
    }
}

上一章:多态
下一章:标准模板库STL(一)

8. 参考资料

  1. C++程序设计
  2. pixiv illustration: 二人だけの楽園

9. 免责声明

※ 本文之中如有错误和不准确的地方,欢迎大家指正哒~
※ 此项目仅用于学习交流,请不要用于任何形式的商用用途,谢谢呢;


在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值