实习面试总结

实习面试总结

所有java和CPP相关问题都是在一面中提到的,因此部分与CPP,java关系不大的也被列入其中。算法部分是一面和二面过程中共同提出的,二面还会问到项目问题,各人不同,不作总结

机器学习相关知识

SVM
adaboost
LR比SVM差的原因

基础知识

MySQL

存储引擎

详细情况过于复杂,如想了解请自行百度,这里只说说明一些常用引擎的区别

  1. MyISAM
    默认存储引擎。MyISAM不支持事务、也不支持外键,但其访问速度快,对事务完整性没有要求。对全文索引的支持较好。
  2. InnoDB
    提供了具有提交、回滚和崩溃恢复能力的事务安全。但是比起MyISAM存储引擎,InnoDB写的处理效率差一些并且会占用更多的磁盘空间以保留数据和索引。自动增长列必须是索引。
  3. memory
    使用散列索引,不可以使用可变长度类型。数据存放在内存中,但是表的元数据存放在磁盘上。
  4. merge
    一组MyISAM表格的组合。对merge的插入、更新和删除都是对其内部MyISAM表的操作。

    事务隔离级

    定义
    数据库在被多线程/进程并发访问时,会出现下面的不确定情况:
  5. 更新丢失
    两个事务都同时更新一行数据,一个事务对数据的更新把另一个事务对数据的更新覆盖了。
  6. 脏读
    一个事务读取到了另一个事务未提交的数据操作结果。
  7. 不可重复读
    一个事务对同一行数据重复读取两次,但是却得到了不同的结果。
    有下面两种情况:
    • 虚度
      事务T1读取某一数据后,事务T2对其做了修改,当事务T1再次读该数据时得到与前一次不同的值。
    • 幻读
      事务在操作过程中进行两次查询,第二次查询的结果包含了第一次查询中未出现的数据或者缺少了第一次查询中出现的数据(这里并不要求两次查询的SQL语句相同)。这是因为在两次查询过程中有另外一个事务插入数据造成的。
      为了避免这些情况,SQL定义了四个事务隔离级:
  8. 未授权读取
    允许脏读取,但不允许更新丢失。如果一个事务已经开始写数据,则另外一个事务则不允许同时进行写操作,但允许其他事务读此行数据。该隔离级别可以通过“排他写锁”实现。
  9. 授权读取
    允许不可重复读取,但不允许脏读取。这可以通过“瞬间共享读锁”和“排他写锁”实现。读取数据的事务允许其他事务继续访问该行数据,但是未提交的写事务将会禁止其他事务访问该行。
  10. 可重复读取
    禁止不可重复读取和脏读取,但是有时可能出现幻影数据。这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。
  11. 序列化
    提供严格的事务隔离。它要求事务序列化执行,事务只能一个接着一个地执行,但不能并发执行。如果仅仅通过“行级锁”是无法实现事务序列化的,必须通过其他机制保证新插入的数据不会被刚执行查询操作的事务访问到。
    MySQL实现
    默认为可重复读取。InnoDB的可重复读取不会造成幻读。

    java

    hashSet实现

    hashSet使用数组+链表的实现方式。数组长度为10,哈希函数为将存储元素转化为string,取每个字符串的首字符的ascall码作为hash函数的输入,散列函数h(x)=x%10。

    GC机制以及存在问题

    三面面试官问到的,因为和java相关,所以放在这里
    GC机制本身比较复杂,而且这是在面CPP的时候三面问的⊙﹏⊙‖ 所以只说下问题,GC机制本身请自行百度。
  12. 静态集合类形成的对象引用
    Static Vector v = new Vector();
    for (int i = 1; i\<100; i++)
    {
    Object o = new Object(); 
    v.add(o); 
    o = null; 
    
    }
  13. 当集合里面的对象属性被修改后,再调用remove()方法时不起作用
  14. 各种连接,数据库连接,网络连接,IO连接等,显示调用close关闭后才能被GC回收

    CPP

    cpp中vector的实现

    c和cpp中static的区别

    const和#define区别

    const常量有数据类型,而宏常量没有数据类型。编译器可以对前者进行类型安全检查,而对后者只进行字符替换,没有类型安全检查,并且在字符替换中可能会产生意料不到的错误(边际效应);
    有些集成化的调试工具可以对const常量进行调试,但是不能对宏常量进行调试。在CPP程序中只使用const常量而不使用宏常量,即const常量完全取代宏常量。

宏常量是为了向下兼容c加入的

extern “C”

指明该段代码以C语言而不是CPP编译
之所以采用这种方式,是因为两种语言之间的一些差异所导致的。由于CPP支持多态性,也就是具有相同函数名的函数可以完成不同的功能,CPP 通常是通过参数区分具体调用的是哪一个函数。在编译的时候,CPP 编译器会将参数类型和函数名连接在一起,于是在程序编译成为目标文件以后,CPP 编译器可以直接根据目标文件中的符号名将多个目标文件连接成一个目标文件或者可执行文件。但是在C 语言中,由于完全没有多态性的概念,C 编译器在编译时除了会在函数名前面添加一个下划线之外,什么也不会做(至少很多编译器都是这样干的)。由于这种的原因,当采用CPP 与C 混合编程的时候,就可能会出问题。

引用传递

没啥好说的,注意下与指针传递的区别

初始化参数列表存在意义

首先说明构造函数执行的2个阶段:

  1. 初始化阶段
    所有类类型(class type)的成员都会在初始化阶段初始化,即使该成员没有出现在构造函数的初始化列表中。
  2. 计算阶段
    一般用于执行构造函数体内的赋值操作
    使用初始化列表主要是基于性能问题,对于内置类型,如int, float等,使用初始化类表和在构造函数体内初始化差别不是很大,但是对于类类型来说,最好使用初始化列表,为什么呢?由上面的测试可知,使用初始化列表少了一次调用默认构造函数的过程,这对于数据密集型的类来说,是非常高效的。

    堆和栈的区别

    直接说下c或cpp编译之后的内存分的部分吧:
  3. 栈区
    由编译器自动分配释放,存放函数的参数值,局部变量的值等。其
    操作方式类似于数据结构中的栈。
  4. 堆区
    一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回
    收。注意它与数据结构中的堆是两回事,分配方式类似于链表。
  5. 全局区
    全局变量和静态变量的存储是放在一块的,初始化的全局变量和静态变量在一块区域,未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。程序结束后由系统释放。
  6. 文字常量区
    常量字符串就是放在这里的。程序结束后由系统释放
  7. 程序代码区
    存放函数体的二进制代码。

    进程通信方法

  8. 管道
    管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。
  9. 信号量
    信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
  10. 消息队列
    消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。
    • 实现:
      一面的面试官特意问了一下消息队列的实现。目前来说,消息队列是linux内核以链表的形式实现的(居然不是队列 (┬_┬) ),有POSIX和system V两种,其中system V的消息队列和内核同生共死,内核启动时System V消息队列被初始化,内核关闭时会清空System V的消息队列。
  11. 信号
    信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。
  12. 共享内存
    共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。
  13. 套接字
    没啥可说的
  14. 有名管道(named pipe)
    有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。

    算法

    倒序输出链表

    没啥可说的。

    求数组中最小的k个数

    编程之美2.5,思路:模仿快排,时间复杂度(Nlogk)
    附加条件:已知范围为0-1000
    不清楚最优解

    给一个记录访问IP的文件,求出现次数最多的IP

    不清楚最优解

    判断单链表是否有环

    不清楚最优解,普遍做法是设置fast和slow

    给定N,求N的阶乘末尾0的个数

    编程之美2.2,比较简单

    给定一排好序的数组和一个数字,该数字可能由数组中2个数字相加,求这两个数字

    编程之美2.12,算法比较简单

    快排

    没啥可说的

    序列化二叉树

    个人做法不同吧,应该没有什么最优

    设计缓存系统

    三面出的技术问题,当场直接跪了╮(╯﹏╰)╭
    场景如下:百度有三万名攻城师,通过ID可以得到攻城师的所有信息。现将所有攻城师的信息录入缓存系统(注意是全部存在缓存里。。。。。实在不明白这为啥叫缓存),设计该系统(表现为java的一个类),该类中有一个Info get(ID)的方法。要求get运行的速度尽可能快

    在不使用辅助数据结构(栈、数组等)的情况下将一个英语句子的单词顺序颠倒,同时单词内部字符顺序不变。如输入I’m a student,输出 student a I’m

    这是春雨的一面问题,感觉很有意思,当时也是误打误撞做出来的,所以贴在这里。算法本身很简单,但是想到比较困难。
    算法分为两步:第一步,颠倒所有单词的字符顺序,句子中的单词顺序不变。以上句为例,第一步之后的输出为tneduts a m’I;
    第二步,将第一步的句子倒序输出。