【C++笔试强训】第九天

选择题

image-20230331150941142

解析:函数的形参是引用类型,我们直接传变量本身就可以。

形参的改变也会引起实参的改变,叫做输出型参数。

image-20230331150948176

解析:本题考查内存申请和释放问题。在C++中,内存申请和释放尽量要匹配使用:malloc/calloc/reallocfree匹配使用;newdelete匹配使用;new[]delete[]匹配使用。

使用new申请空间和delete销毁空间时过程:

1.new T :调用operator new()申请空间,其实operator new()函数内部还是使用malloc申请空间,然后调用T的构造函数对申请的空间进行初始化;

delete p:先调用析构函数释放p指向对象中的资源,再调用operator delete()释放p所指向的空间,实质上函数内部是使用free释放空间的。

2.new T[]:调用operator new[]()申请空间,其实内部是使用operator new()申请空间,然后调用NT的构造函数对申请的空间进行初始化;

delete[] p:先调用N次析构函数释放p指向的N个对象中的资源,再调用operator delete[]()释放p所指向的空间,实质上函数内部是调用operator delete()释放空间的。

new [5]申请5个ClassA类型的空间,同时会调用构造函数5次,对于new []申请的空间,要用delete []进行释放,如果用delete进行释放,很有可能会报错,所以题目中delete只会释放一个空间,调用一次析构函数。

image-20230331150956631

解析:malloc是在堆上申请空间,而new内部也使用malloc申请空间,所以new动态申请的内存在堆区。

image-20230331151002751

解析:静态成员特性:

1.静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区 ;

2.静态成员变量必须在类外定义,定义时不添加static关键字,类中只是声明

3.在类外访问静态成员变量(成员变量访问限定符为public)时:对象.静态成员变量 || 类名::静态成员变量

4.静态成员函数没有隐藏的this指针,不能访问任何非静态成员

5.静态成员也是类的成员,受public、protected、private 访问限定符的限制

要使用静态的数据成员的时候,在静态成员名前面加上类名和作用域符号(::),静态成员属于类的所有对象,要在类域外面进行定义初始化,当然静态变量要加上static

在类外这样定义和访问:

image-20230331151011083

解析:class定义的类的默认访问权限是私有private,struct定义的类的默认访问权限是public

image-20230331151018556

解析:类的非静态成员函数形参中有隐藏的this指针,参数表中没有任何参数说明是一个一元运算符的重载;前置运算符重载为成员函数时,参数列表中不给参数,但是后置运算符一般会给一个参数以示区别,比如前置++,用operator+();后置++,用operator+(int)区分。

image-20230331151133565

解析:obj(1)和obj(2)是直接调用构造函数,obj3(obj1)调用拷贝构造,所以这里会打印112,然后就是return 0,调用析构函数,先构造的后析构,然后会打印444。

image-20230331151142702

解析:静态成员不能在类内初始化,要在类外初始化;

静态成员为类对象所共有的,可以被类对象调用;

既然是成员就可以被访问限定符的限定;

公共成员可以直接用类名进行调用。

image-20230331151148908

解析:如果把构造函数设成私有,那么在类外new一个空间的时候就会报错;如果把析构函数设成私有,那么可以用new类创建,但是不能直接用delete释放空间,可以通过在类里面创建一个函数专门用来调用delete,能够释放空间。

image-20230331151220770

解析:函数模板格式:template<typename T1, typename T2,......,typename Tn> ,注意:typename是用来定义模板参数关键字,也可以使用class,不能使用struct代替class

编程题

1.另类加法

image-20230329211141871

答案解析:本题的意思是自己实现加法,不适用现成的运算符,考察大家对于运算符的灵活运用

解题思路:
本题可以通过位运算实现,具体实现如下:
两个数求和,其实就是 求和后当前位的数据+两个数求和的进位

例如:
1 + 2; 00000001 + 00000010
求和后当前位的数据: 00000011 ; 求和后的进位数据: 没有进位,则 00000000
两者相加,则得到: 00000011 就是3
2 + 2; 00000010 + 00000010
求和后当前位的数据: 00000000, 1和1进位后当前为变成0了
求和后进位的数据: 00000100, 两个1求和后进位了
相加后得到: 00000100 就是4

求和后当前位的数据:简便的计算方法就是两个数进行异或 00000001 ^ 00000010 -> 00000011
求和后进位的数据:简便的计算方法就是两个数相与后左移一位 (00000010 & 00000010) << 1
所以这道题使用递归更加容易理解

个人理解:当使用^计算时,得到的是两个数中相同权重位不同数值的结果;使用&计算得到的是相同位中都为1计算得到的结果,计算的也就是需要向前进位的那一位,所以计算得到的结果左移一位;本来应该是这两个计算结果相加得到最终结果,但是不允许使用+号,所以再次将两个结果进行递归计算。image-20230330084752318

class UnusualAdd {
public:
    int addAB(int A, int B) {
        // write code here
        if(A == 0) 
            return B;
        if(B == 0)
            return A;
        int sum = A ^ B;//不考虑进位时候相加的结构
        int ret = (A&B) << 1;//计算进位的数据
        return addAB(sum, ret);
    }
};

image-20230330085154330

/*
异或是不进位的加法
0001 ^
0011
0010

相与后左移一位即可得到进位的数据

0001 &
0011
0001 << 1
0010

0010 ^
0010
0000

0010 &
0010
0010 <<
0100 最终结果

*/
class UnusualAdd {
public:
    int addAB(int A, int B) {
        if(A == 0) // 任意一个为0的时候就截止
            return B;
        if(B == 0)
            return A;
        int noCarry = A^B;
        int carry = (A&B)<<1;
        return addAB(noCarry, carry);
    }
};
/*
最终结果其实就是 A^B + (A&B)<<1
但是不能使用+,因此循环处理右边的部分,直到为0才出来
*/
class UnusualAdd {
public:
    int addAB(int A, int B) {
        while(B != 0){
            int a = A^B;
            int b = (A&B)<<1;
            A = a;
            B = b;
        }
        return A;
    }
};

2.走方格的方案数

image-20230329212102918

解析:本题为求取路径总数的题目,一般可以通过递归求解,对于复杂的问题,可以通过动态规划求解。此题比较
简单,可以通过递归解答。
【解题思路】:

| 1 | 2 | 3 |

| 4 | 5 | 6 |

| 7 | 8 | 9 |

  1. 对于上面的nm(33)的格子,有两种情况
    a. 如果n或者m为1,则只有一行或者一列,从左上角走到右下角的路径数为n + m
    比如: 1 * 1格子,可以先向下走,再向右走,到达右下角;或者先向右走,
    再向下走,到达右下角,共两条,即 1 + 1 = 2,对于1 * m和 n * m的
    情况同学们自己画一下
    b. 如果n,m都大于1,那么走到[n][m]格子的右下角只有两条路径,
    <1>: 从[n - 1][m]格子的右下角向下走,到达
    <2>: 从[n][m - 1]格子的右下角向右走,到达
    所以走到[n][m]格子的右下角的数量为[n-1][m] + [n][m - 1],可以通过递归实现,情况a为递归的终止条件。
#include<iostream>
using namespace std;
int pathNum(int n,int m)
{
    if(n > 1 && m > 1)
        //b情况,递归
        return pathNum(n-1,m) + pathNum(n,m-1);
    else if(((n >= 1)&&(m == 1))||((n == 1)&&(m >= 1)))
        // a情况,终止条件
        return n + m;
    else
        //格子为0时, 路径为0
        return 0;
}
int main()
{
    int n,m;
    while(cin>>n>>m)
    {
        cout<<pathNum(n,m)<<endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_53943591/article/details/129908423