每日一练(二十八)

1.11 常成员相关选择题

对于类的常成员函数的描述正确的是()

A.常成员函数不修改类的数据成员
B.常成员函数可以对类的数据成员进行修改
C.常成员函数只能由常对象调用
D.常成员函数不能访问类的数据成员

答案:A

常成员函数含义是通过该函数只能读取同一类中的数据成员的值,而不能修改它。

常对象只能调用常函数成员,不能调用非const 函数成员问题。

1.12 C/C++编译考察

C/C++的编译包括几个部分?

答案:编译、汇编、链接

具体的包括:预处理、编译、汇编、链接

1、预编译:预处理器对c程序进行一些预处理工作,例如对宏定义的变量进行替换;

​ 1)将所有的#define删除,并展开所有的宏定义;

​ 2)处理所有的预编译指令,例如:#if,#elif,#else,#endif;

​ 3)处理#include预编译指令,将被包含的文件插入到预编译指令的位置;

​ 4)添加行号信息文件名信息,便于调试;

​ 5)删除所有的注释:// /**/;

​ 6)保留所有的#pragma编译指令,因为在编写程序的时候,我们经常要用到#pragma指令来设定编译器的状态或者是指示编译器完成一些特定的动作;

​ 最后生成.i文件;

​ 总的来说,包括(1)去注释 (2)宏替换 (3)头文件展开 (4)条件编译

2、编译:编译器将c语言程序翻译成汇编语言程序;

​ 1)扫描,语法分析,语义分析,源代码优化,目标代码生成,目标代码优化;

​ 2)生成汇编代码;

​ 3)汇总符号;

​ 4)生成.s文件;

3、汇编:汇编语言通过汇编器编译成可重定位目标程序.o,与之相反称为反汇编;

​ 1)根据汇编指令和特定平台,把汇编指令翻译成二进制形式;

​ 2)合并各个section,合并符号表;

​ 3)生成.o文件;

4、链接:将目标文件和所需的库函数用链接器进行链接,常见的链接器有Unix;

​ 1)合并各个.obj文件的section,合并符 号表,进行符号解析;

​ 2)符号地址重定位;

​ 3)生成可执行文件;

1.13 union含数组 struct内存对齐

typedef union {
    Short i;
    int k[5];
    char c;
} Mat;
Typedef struct {
    int i;
    Mat j;
    double k;
}Like;

则语句 printf("%d",sizeof(Like)+sizeof(Mat));的执行结果是?
答案:32

Mat里面最大元素是int k[5]占20Byte,所以Mat的大小就是20Byte。

注意!!!Mat的长度大小是20Byte,并不是说Mat是一个以20Byte为单位的新数据,而是在内存中开辟了一段大小为20Byte的空间,至于空间中的数据类型是什么,是不确定的。Union只要保证连续的空间是最大的范围就行

其实struct与union一样,都是申请一段连续的内存空间,只不过struct更注重内存对齐。

所以在Like中,最大的成员是double k应该以8Byte对齐,也就是Like的大小是8的整数。然而在内存分配的时候Mat是作一个20Byte的空间,而且可以使用这20Byte的空间进行struct的内存对齐的。

所以在Link中,以8Byte对齐,int i占4Byte,从union中接着放4Byte来对齐8Byte,union中还剩下16Byte正好对齐,接着double k8Byte对齐,所以总的大小就是8+16+8=32Byte。

所以当union变换时:

typedef union {
    short i;
    int k[3];
    char c;
    float f;  //即使有float也不影响下面struct对齐的时候,给int i借4Byte
} Mat;
typedef struct {
    int i;
    Mat j;
    double k;
}Like;
sizeof(Like) = 24

根据上面所说,union只是一个12Byte的空间,可以在struct中被用来填充内存对齐,所以在struct中int i4Byte向union借了4Byte用来对齐8Byte,union剩下8Byte正好对齐,double k正好对齐,所以总的大小就是8+8+8=24。

union 写得好的博客:https://blog.csdn.net/huqinweI987/article/details/23597091?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.control

1.14 为什么ARM中FIQ比IRQ快

三点:

  • FIQ的中断优先级比IRQ高,FIQ可以打断IRQ,IRQ不可以打断FIQ
  • FIQ有私有寄存器(r8~r12),不需要压栈保存寄存器,可以直接中断
  • FIQ位于异常中断向量表的末尾,可以直接在异常中断向量表之后编写FIQ的处理程序,无须结果跳转

1.15 算法:数组中重复的数字

力扣:https://leetcode-cn.com/problems/shu-zu-zhong-zhong-fu-de-shu-zi-lcof/

方法一:遍历数组

遍历数组,判断数组是否在哈希表中。

方法二:原地置换(特定情况)

由于此数组的大小为n,数组元素的范围也是0~n-1,所以没有重复的情况下应该是下标i对应的位置元素就是i。

所以,我们可以遍历数组,在遍历中不断纠正数组元素与下标的位置关系!!!这就是原地置换,核心思想就是不断纠正下标与元素的对应关系。

当下标与元素不对应的时候,就要纠正了,将元素对元素对应下标上的元素互换位置(我们默认唯一下标对应唯一元素的),交换后再次判断下标与元素的关系,就这样一直判断。

但是实际上我们知道是有重复元素的,也就是重复元素会占用其他元素的下标,我们上面交换的过程就是验证对应下标上的元素是不是当前要判断的元素,如果是!说明当前元素在那个下标上重复了。

在当前下标的基础上纠正,如果找到对应的元素,那就纠正下一个,如果在纠正的过程中遇到了重复的元素,那就退出。

第一版代码:

int findRepeatNumber(int* nums, int numsSize){
    int i, k;

    for (i = 0; i < numsSize; ++i) {
        while (nums[i] != i) {    //一直纠正
            if (nums[i] == nums[nums[i]]) {   //找到重复
                return nums[i];
            }
            /* 不重复且位置错误 纠正 */
            k = nums[i];
            nums[i] = nums[nums[i]];
            nums[nums[i]] = k;
        }
    }

    return -1;
}

但是一直提示超出时间限制

使用C++提交后就ok:

class Solution {
public:
    int findRepeatNumber(vector<int>& nums) {
        int k;
        for (int i = 0; i < nums.size(); ++i) {
            while (nums[i] != i) {     //纠正开始
                if (nums[i] == nums[nums[i]]) {  //判断重复
                    return nums[i];
                }
                swap(nums[i], nums[nums[i]]); //交换纠正
            }
        }
        return -1;
    }
};

因为是最多一次遍历就可以得出,所以时间复杂度是O(n),另外所有的操作都是基于原数组的,所以空间复杂度为O(1)。

考点

  • 一维数组在内存中是连续存储的,而且可以根据下标随机存取,所以可以根据下标与元素的关系直接定位
  • 考察了应聘者的分析能力,这道题刚看起来是比较复杂的,但是是有规律性的,比如题中给出的长度为 n;元素范围0~n-1;只要求出任意重复元素,这些都是在提示规律,和数组的长度、下标、随机存取特性有关
  • 还要考察无效输入的情况:空指针、包含范围之外的元素等
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值