秋招面经搜集总结

2018.7.23
下面是个人在秋招过程中搜集的一些面经,分享出来如下:

——————————————————————————————————————————————————————

1.进程和线程的区别?(什么样资源在两个线程共享)

——进程是资源分配的最小单位,线程是cpu调度的最小单元
——一个进程有多个线程,多个线程可以并发执行
——进程的创建退出操作系统为其分配资源,切换线程需要保存这些资源,进程切换开销大,同一个进程的线程共享该进程的资源,故线程仅仅有一些自己独立的寄存器堆栈资源,线程之间切换开销小
——进程之前有专门的通信方式:管道、信号量、消息队列、共享内存、socket套接字,线程之间通信主要靠锁和信号量来完成。

2.c++怎么写是分配栈内存?

——class node,node a = null; a = b;临时变量,分配栈内存
——class node,node
a = new node(b); 分配堆得内存,需要用delete删除

3.new和malloc区别?(构造函数在什么时候创建的?回答new和malloc重要区别)

——new分配内存的时候可以动态绑定,在程序运行的时候绑定资源,是一种操作符
——malloc不能动态绑定,只能在编译之前确定内存的大小,是一种库函数
——new分配内存之后,创建对象自动执行构造函数,销毁自动完成析构,malloc则没有这一过程
——new自动分配对象内存空间,进行安全性检查,malloca指定分配内存空间,不进行安全性检查

4.STL能够写new vector这样操作?(vector resize特点capacity)

——vector创建的时候会创建多的容量,当超过这一部门多的容量的时候,会重新resize分配一个原容量两倍的容器,然后将原数据拷贝到新分配的容器中。

5.为什么要用虚函数?虚函数一般在编译器怎么实现多态?

——函数在编译的时候首先进行命名的检查,通过命名的检查找到函数,然后检查该函数是否是虚函数,如果是非虚函数,直接静态绑定对应的函数指针,是虚函数,则为该对象创建虚函数表,并创建虚函数表的指针,加入该结构体重。等到运行阶段,对象绑定的函数不同,将动态将该对象绑定给覆盖的函数,从而同一个函数实现不同的功能,即为多态。

6.什么是纯虚函数?纯虚函数可以不覆盖吗()

——不能,纯虚函数就是一种接口,没有实体,在子类中必须覆盖父类的纯虚函数,才能调用该纯虚函数。
——————————————————————————————————————————————————————

1.我看你的简历上有写计算机网络相关的,那你能讲下tcp/ip,time_wait?

——4次握手,3次挥手,
——timewait为了防止最后一次挥手,服务器端没有收到挥手的确定信号,这个时候服务器会重新发送挥手信息,客户端在timewait的等待时间仍然可以接受到这个挥手,从而保证正常的关闭tcp.

2.字符串匹配问题,判断一个字符串有木有在另一个字符串里面出现

——hashmap

3.第二个算法题 应该是和网络相关的,大概意思是有65535个数据中每次取五个,要求取的不重复,

——为65536个数据建立hashmap表,之前取得数据就在hashmap里面置true,没有即为false,每次随机取数据,如果发现是true则重新取一次即可。

4.一个整数数列,元素取值可能是0~65535中的任意一个数,相同数值不会重复出现。0是例外,可以反复出现。

请设计一个算法,当你从该数列中随意选取5个数值,判断这5个数值是否连续相邻
注意:

  • 5个数值允许是乱序的。比如: 8 7 5 0 6
  • 0可以通配任意数值。比如:8 7 5 0 6 中的0可以通配成9或者4
  • 0可以多次出现。
    ——扑克牌顺子问题,首先排序,然后计算每个相邻元素之间的gap值有多大,然后计算为0的值有多大,然后比较0的个数和gap的
    个数的大小,0个数大于等于即可。

4.判断结构体是否相等

——重载等于号,记住需要判断指针指向的内容是否相等。

5.位域

——
位域 :
有些信息在存储时,并不需要占用一个完整的字节, 而只需占几个或一个二进制位。例如在存放一个开关量时,只有0和1 两种状态, 用一位二进位即可。为了节省存储空间,并使处理简便,C语言又提供了一种数据结构,称为“位域”或“位段”。所谓“位域”是把一个字节中的二进位划分为几 个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。 这样就可以把几个不同的对象用一个字节的二进制位域来表示。位段成员必须声明为int、unsigned int或signed int类型(short char long)。

struct bs     
{     
    unsigned a:1;     
    unsigned b:3;     
    unsigned c:4;     
} bit,*pbit;     
bit.a=1;     
bit.b=7; //注意:位域的赋值不能超过该域所能表示的最大值,如b只有3位,能表示的最大数7,若赋为8,就会出错   
bit.c=15;

printf("%d,%d,%d/n",bit.a,bit.b,bit.c);
pbit=&bit;
pbit->a=0;
pbit->b&=3;
pbit->c=1;
printf("%d,%d,%d/n",pbit->a,pbit->b,pbit->c);
通过:该位域的大小,例如a是1bit,b是3bit,c是4bit

6.fopen相关的,我记得大概意思是windows下和linux下用法区别

——形式:
windows:
FILE *fp = fopen(“D:\quick_sort.c”, “r”);
linux:
FILE *fp = fopen("/home/quick_sort.c", “r”);
——参数区别:
UNIX/Linux 不分文本文件和二进制文件,而Windows下时区分的。考虑程序平台兼容性,若以二进制形式打开,最好加‘b’
windows,一般以二进制打开,最好加上b,例如rb
linux,直接r即可,不需要额外指明文本还是二进制文件
——————————————————————————————————————————————————————

2018.7.24

1.说一下new和malloc的区别(我:new是分配+构造,malloc只分配不构造;new是操作符,malloc是库函数)

说一下虚拟地址是怎么映射到物理地址的,说一下这个过程(操作系统不熟完全记不得这个东西了,我就扯了说有个转换表这样的东西,虚拟地址前几位是找到对应的页,然后后面几位对应的就是偏移量这样子,然后他说这只不过是找到页表而已。我也不知道是什么,就说不大清楚了)
——通过NAT页表或者段表找到虚拟地址对应的表项,表项中存放的就是逻辑地址到物理地址的映射。

2.STL有了解过吗?里面空间分配是怎么样的?(然后我说了用allocator类来实现空间分配,有一级配置器二级配置器,还没说完就被打断了)

——有两级配置器,第一级是分配大块内存的,第二季是小块内存,16个不同区间的内存,最小的8kb,最大的128kb,每个不同内存块挂在对应的空闲链表上,分配的时候找空闲链表上最小的内存块分配。

3.不是问你这些,我换个说法吧,如果用让你写一个STL的空间配置器,这个配置器需要经常分配大量的小内存,但大量的分配小内存会造成内存碎片,你会怎么解决这个问题?(然后就跟他扯了一些二级配置器是怎么实现的)

——slab机制,分配一些不同大小的数据块,同空闲链表来组织。

那如果用你实现的配置器分配的空间是怎么释放的?(然后我说用allocator分配就用deallocator释放,然后释放的内存就放回到空闲块链表中)
——用allocator分配就用deallocator释放,然后释放的内存就放回到空闲块链表中。

我是问这些释放的内存怎么交回给系统?(我:额。。。这个程序关掉就交回去咯)
——释放内存只有,操作系统负责回收堆里面开辟的这些内存。

4.那假设系统只有100m内存你已经用了20m了,这样下去不是会爆内存吗?(我:这个我不大清楚了)

对c了解不?(我:了解,但写的比较少)
那问你个c里面数据结构体的问题,能不能直接用内存比较的方法比较两个struct对象?(我:不行,struct会有内存补齐。然后想举个例子说明一下为什么不行,想到一半就卡壳了,对面就直接说行了不用说了。现在想了下应该是补齐之后内存地址里面的垃圾值会造成影响,当时面到后面都有点乱了,脑子宕机了T-T)
——内存对齐,后面对齐的内存地址里面的垃圾值会造成影响。

5.网络这一块有了解过吗(我:学过计网)

那tcp里面的time_wait状态知道吧,说一下(我:保证服务器重发一个FIN之后,客户端也能对这个进行应答,然后也保证处理到迟到的数据包)
——防止客户端重传,可以接收到。

6.如果有4亿个数,你只有1G内存,你怎么判断某个数已经出现了(我:这个可以用位图来做吧,四亿个位,数n出现了第n位就置1,最后判断某个位是不是1就行)

——bitmap用一个bit来判断某个数出现或者没有出现。

——————————————————————————————————————————————————————

1、一个C++源文件从文本到可执行文件经历的过程

——主要经历的是源文件,预编译,编译,汇编,链接,可执行文件。
——编译,将高级语言翻译成为汇编语言,同时进行语法上的优化
——汇编,将汇编语言转换成为计算机能够识别的机器码
——链接,将多个文件彼此关联起来,形成一个可执行文件

2、#include 的顺序以及尖叫括号和双引号的区别…

——如果该文件用到其他的文件,那么就需要先引用其他的文件,在引用自己需要的文件。
——尖括号一般搜索默认路径下的头文件,一般引用库文件;双引号一般搜索用户的工作目录的路径下的头文件,一般引用自己写的头文件。

3、进程和线程,为什么要有线程

——为了更好的给cpu调度和更好的并发,在传统的进程中提高了并发量,提出了线程,线程就是轻量级的进程。

4、C++11有哪些新特性

——语法上:auto,for:,nullptr
——STL容器:unordered_map/set
——多线程:thread的使用
——智能指针:shared_ptr

5、为什么可变参数模板至关重要,右值引用,完美转发,lambda

——模板很重要,因为可以不考虑数据的类型,通过模板可以写出通用的逻辑来,例如STL里面的容器
——右值引用是为了消除临时变量之间的拷贝浪费的构造析构的资源,右值引用可以指向临时变量并且把临时变量转移给左值变量。
——lambda表达式:就是内嵌的匿名函数,用以替换独立函数或者函数对象,并且使代码更可读

6、malloc的原理,brk系统调用干什么的,mmap呢

——malloc用于分配内存,mmap用于将物理内存映射到用户空间的一个文件

7、C++的内存管理方式,STL的allocaotr,最新版本默认使用的分配器

——两次结构,第一层分配大块连续数据,第二层slab机制,预先分配小块内存,用空闲链表来维护。

8、hash表的实现,包括STL中的哈希桶长度常数。

——采用的是开放式寻址法,哈希桶为映射单元,桶内部用链表来维护。
——开始确定一个素数,根据表的填装因子,然后表满了就以两倍的容量进行扩展,移动数据到新的表中。

9、hash表如何rehash,怎么处理其中保存的资源

——两倍的容量进行扩展,移动数据到新的表中

18、epoll怎么实现的

——epoll是通过回调函数和就绪队列完成的,当socket监听到事物的时候,会触发回调函数,将这个套接字挂在就绪队列上,并通知应用层去取数据。

20、手撕代码:1)给定一个数字数组,返回哈夫曼树的头指针。2)最长公共连续子序列。

22、单核机器上写多线程程序,是否需要考虑加锁,为什么?

——在单核上,多个线程执行锁或者临界区时,实际上只有一个线程在执行临界区代码,而核心也只支持一个线程执行,因此不存在冲突。如果某个线程持有锁,那只有其他线程不会被调度到CPU上执行,影响的只是持有和释放锁的时间,处理器时刻在运行着。但是在多核上运行时,锁或临界区会导致其余处理器空闲而只允许一个处理器执行持有锁的那个线程,这是一个串行的过程,会影响性能。
——不需要加锁,因为处理器同一个时刻只会有一个线程去访问临界区,不存在冲突的情况。

23、线程需要保存哪些上下文,SP、PC、EAX这些寄存器是干嘛用的

——堆栈指针SP
——程序计数器PC
——累加器寄存器EAX

24、HTTP和HTTPS的区别,HTTPS有什么特点,带来的好处和坏处,怎么实现的

——https在http上增加了ssh,提高了安全性的保证。
——好处:安全性,坏处:影响相应延时,证书需要第三方费用
——怎么实现:加上ssh的证书认证

25、线程间的同步方式,最好说出具体的系统调用

——生产者消费者模型,实例就是命令队列,向命令队列里面加入命令的时候,给队列加锁,同时命令执行线程没有命令的时候进入睡眠状态,命令添加完成的时候唤醒命令执行线程,去命令即可。

26、哈希表的桶个数为什么是质数,合数有何不妥?

——取质数更容易减少冲入,取合数冲突较多,这是因为质数只能被本身和1除尽,合数可以被其他数除尽,除尽的数就都是冲突点,冲突明细较多。
——————————————————————————————————————————————————————

1,讲项目

2,项目用到了redis,讲一下redis的主从复制怎么做的。。讲了挺久的。。

3,写代码,去掉字符串中的空格空格,C语言实现(虽然写出来了,但是面试官说4行代码就能写出来这个。。)(2年没写过C和Cpp了崩溃。。)

for(int i=0;i<str.size();i++)
    if(str[i] == " ")
         str.erase(str.begin()+i);

4,如何把一个文件快速下发到100w个服务器

(面试官之后说你可以想想迅雷是怎么做到下载速度那么快的)
——
如果集中式地放在一个服务器或缓存上的话,带宽、连接都会遇到问题。只说idea的话。

树状:
1. 每个服务器既具有文件存储能力也应具有文件分发能力。
2. 每个服务器接收到文件之后向较近的服务器分发,具体类似多叉树,应该挺快的。

索引状:
1. 设置1000个缓存服务器,文件先下发到这些缓存上。(具体多少缓存、分几层缓存和具体业务有关。)
2. 每个缓存服务器接收1000个服务器取文件。
p2p网络:每个节点既能接收也能发出,朝自己近的网络发出。

5,如何判断一个图是否连同?(开始说DFS,面试官说不满意,后来说并查集)

——DFS和BFS有的步骤都是从一个顶点开始,然后判断该顶点是否被访问,而且该顶点和其他顶点是否有关系,若有关系并且没有访问过,就往下访问,要是无向图是连通的,那么这个过程会依次下去遍历所有节点。所以通过这个特性,就可以设置一个全局变量count去记录,看最后count的值和顶点数是否相同,若相同则说明是无向连通图

——————————————————————————————————————————————————————

C++/C的内存分配,栈和堆的区别,为什么栈要快

——c++一般对于堆得分配是用new,c对于堆的分配是用malloc
——堆是用户自己分配和回收资源的,栈由系统自动分配资源并回收
——栈是有操作系统自动分配资源并回收,操作系统底层支持这一类数据结构,其中会为栈分配专门的地址寄存器用来存放栈的地址,压栈和出栈都有专门的指令,而堆得分配是由cpp的库函数提供的,会有一定的算法以及搜索分配块的机制,速度相比栈来说肯定是慢了。

C++和C的区别

——面向对象,面向过程

TCP三次握手

——最小可靠性的保证
——客户端第一次握手,表示能发,服务器接受,表示能收,然后发送确认信号,表示能发,客户端收到确认信息,表示能接受,这样三次握手之后,即保证客户端服务器端能够正常的接收。

给一个坐标系和一个矩形,如何判断矩形在坐标系内(当时没考虑到矩形边没平行x,y轴的情况,此时感觉挂了)

——?????判断点是不是在矩形内部?直接判断点在不在线的同侧或者是异测即可。

如何用一个1立方米的方块占满这个小教室(我:???)

——空间上使用dp,空间上可以从左右上进行塞,这样使用递归可以知道塞满整个房间的步骤和可能性。

——————————————————————————————————————————————————————

为什么内存分配一定要用栈这个数据结构,先进后出?也就是为什么栈是栈?

——因为局部变量分配是按照先后顺序的,函数创建先创建,但是函数只能最后释放,这就是先进后出,有这种操作,所以有了栈这样的数据结构。

整个面试流程是1.hr面试 2.英文逻辑题 3.结对上机测试(2,3的顺序可能变换)

● 结对上机面试就是先问你作业的思想,然后扩充作业题,考察你的编程习惯,快捷键的使用,中间穿插一下基础知识考察,难度还行吧

● 英文逻辑题看懂例子就不难,基于保密就不能说了,反正不难吧。

● 除了一张英文逻辑题的测试卷,没有其他英语考察。

● 问了hr和上机测试的面试官,为什么他们这么认同公司。回答是文化和一种使命感,当时心里想的是和dota2信仰玩家一模一样。
——————————————————————————————————————————————————————

● 实习经历

● C++内存分配

——常规的是new,delete
——stl是allcoated二级内存的分配

● 链表合并(leetcode原题)

——递归或者非递归

● 如何判断内存泄露,野指针是什么,内存泄漏怎么办?

——通过工具判断,vs里面有cmg监测内存泄漏的宏,或者监控进程的内存,观察是否泄漏,野指针就是指向了不存在的内存区域,内存泄漏需要找到泄漏的地方,分析原因,正常释放
——————————————————————————————————————————————————————

3.overload 和overwrite的区别,怎么实现的?返回值不一样可以重载吗?

——第一个是重载,虚函数重载
——第二个是重写,子类就是一个类中的方法同名,但是形参的类型和个数不一样,这叫做重写
——————————————————————————————————————————————————————

1面 评估面

面试官:给我讲讲浏览器输入地址后发生的全过程.(每一个细节都讲)

我:http DNS 三次握手 arp rarp

面试官:讲讲为什么是三次握手,四次挥手

我:2次握手超时数据包会影响很大,三次握手容易遭到syc攻击,四次挥手很多情况下是三次(tcpdump抓)以及常见的粘包,数据包安全.滑动窗口.

面试官:内存分布

我:堆.栈.常量区,静态区

面试官:讲讲虚函数

我:虚函数表,以及虚函数的内存布局,虚函数的局限,c++11的提供的类似虚函数的新函数.两种动态多态实现的区别以及优缺点
——虚函数在编译阶段会生成一个虚函数表的指针,这个指针指向虚函数表,当重载之后,子类的虚函数表指针指向子类的重载的虚函数,当调用虚函数执行的时候会动态绑定到对应的虚函数上。
——这要是虚函数的局限,就是虚指针占用内存空间

面试官:讲讲进程和线程

我:常见的一些书本知识,在寄存器和堆栈上的区别,协程的实現,异步和同步编程.

2面

面试官:类什么时候会析构?

我:局部类变量弹出栈的时候会调用析构,new对象调用delete的时候会析构。

面试官:虚函数底层机制

我:虚函数表,以及虚函数的内存布局

面试官:大区间求和

我:只想出归并

面试官:讲讲codis和redis源码

我:这块很熟,我也讲的很多,包括性能瓶颈,主流公司的网络框架.以及代码改进,面试官还算满意

面试官:讲讲bigtable mapreduce 以及其他著名开源分布式存储代码

我:只看过kafka和缓存
面试官:要多学点

5面(个人感觉最难几乎社招要求)

首先让我自己把tcp/ip讲个遍。

分布式系统分片的极限在哪,linux系统的极限。redis集群最大能支撑多少台物理机,

——数据分片就是讲数据打散写入到不同的机器上,类似于pt,那么问题在于一个环上到底最多能放多少个pt呢,这个问题之前都没想到过,这个题目比较难!!

怎么解决副本一致。

——RSM,catch-up, rebalance

分布式缓存怎么设计,

——memcached的设计思路

配置中心怎么开发,

——OM模块的开发,负责配置文件和升级

zookeeper的原理,

——paxos的具体实现,用来持久化元数据和选举新主节点

二次提交原理。

——先通知,在决策提交。
——————————————————————————————————————————————————————

项目,主题模型

一个数据流,只能访问一次,如何保证访问每个数据的频率相同

——蓄水池抽样算法(reservoid sampling)。具体的思路是:先初始化一个集合,集合中有k个元素,将此集合作为蓄水池。然后从第k+1个元素开始遍历,并且按一定的概率替换掉蓄水池里面的元素。
——先将前k个数取出来放入结果集中,然后从第k+1个数开始遍历。假设遍历到第i个数,以k/i的概率替换掉蓄水池中的某个元素即可。

c++11 future和promise

——不会

epoll,libev优点

——epoll 同步非阻塞的socket监听
——libev事件驱动的监听,不阻塞线程,可以使用多线程完成事件的驱动

构造函数能不能重写(没听清要问什么)

——不能

面向对象的优点:更易维护,增加代码的重用

大文本如何排序

——内部排序,bitmap
——外部排序,桶排序

最优二叉树(我说数据结构比较熟,他说那我考你一个最优二叉树。没答出来,以为是排序二叉树。。如果问我哈夫曼树我就会了。。)

——排序,画出哈夫曼树,确定0 1 位数

栈和队列

栈空间,堆空间,静态区
栈区:有编译器自动分配释放,堆区:由程序员分配释放
静态区:全局变量和未初始化的静态变量

kmeans

——聚类的方法

linux如何扩大分区

——首先unmount卸载盘
——fdisk 查看盘
——resize2fs /dev/sdb1调整分区
——mount重新挂载
——————————————————————————————————————————————————————

map用的是红黑树,和AVL树的区别

——红黑树没有avltree那么强的平衡条件,它只用通过节点的红黑来保证,任意一条路径不能比另外一条路径长出两倍,AVLtree在保持平衡上要不断的旋转调整,增加了额外开销,RB树相对来说,开销较小

map插入和删除需要注意什么

——插入的时候需要先判断,因为key相同坐标插入会覆盖,调用insert会直接返回插入失败
——删除同样,删除之前需要判断

mongodb 和 mysql 差别

——不会

IO多路复用方式的区别

——select poll epoll的区别

如何查看函数所占用的内存

——gdb调试,一步步走,然后用ps监控进程的内存走向

C++多态是怎么实现的,哪些函数不能是虚函数(构造函数,静态函数,inline函数)

——构造函数,静态函数,inline函数不能是虚函数

malloc(0)返回什么:

——如果请求的长度为0,则标准C语言函数返回一个null指针或不能用于访问对象的非null指针。
——————————————————————————————————————————————————————

为什么析构函数要是虚函数,为什么c++没有默认析构函数为虚函数

——在类的继承中,如果基类不定义成虚函数,当有基类指针指向派生类, 那么delete基类指针时,只会调用基类的析构函数,不会调用派生类中派生类的析构函数。
——额,因为不一定有子类???但是c11里面是建议写成析构函数的

1.模板成员函数不可以是虚函数

https://blog.csdn.net/zzuchengming/article/details/51763563
——完全一样,
在非模板类里怎么用虚函数,
就在模板类里怎么用

2.C++里面有很多小类,如果都有虚析构函数,则会对每个类都加一个虚表指针,浪费内存

——这要是虚函数的局限,就是虚指针占用内存空间

——————————————————————————————————————————————————————

1.字符串去空格

——string类型erase即可

2.十六进制转十进制

——16位基数,power乘方函数调用执行

如何求前100大的数

——topk的问题,可以用最大堆,可以用快排思想,当然可以用排序

堆和栈的区别

——系统分配,自动回收
——自己分配,自己回收

全局的const,在函数里面改const的值(没理解面试官问什么)

——利用const_cast去掉const的属性

io多路复用,为什么epoll比较好,什么时候select比较好

——epoll只用拷贝一次数据,epoll回调函数等待队列,不用轮询套接字,epoll内存映射的方法,减少拷贝,epoll支持边缘触发

两种触发方式

——水平触发,触发了之后不断通知上层应用取数据
——边缘触发,只会通知一次,之后不在通知了

进程间通信

——管道、共享内存、消息队列、信号量、套接字

共享单车如何分配

——统计某一段区域的人口密集程度作为优先级权限,按照人口的密集程度进行分配。

有一户家庭,生了两个娃,其中一个是女孩,另外一个是女孩的概率

——1/2

栈实现队列,队列实现栈

STL set用什么实现,为什么用红黑树实现

——因为是有序的,红黑树可以有序,平衡二叉树导致深度太深,avltree插入较多情况旋转效率低,heap是连续数据的存储数据结构。

hash用在什么地方

——kv存储

各种排序空间复杂度和时间复杂度,稳定程度

快排什么时候最不稳定
——以某一个基准交换的时候

linux基本命令

查看进程,线程,函数的cpu占用
——top ps

gdb

字节序,网络序是什么字节序,为什么会有不同的字节序

——字节序分为大端字节序和小端字节序
● 大端字节序是指一个整数的高位字节(32-31bit)存储在内存的低地址处,低位字节(0-7bit)存储在内存的高地址处。
● 小端字节序是指一个整数的高位字节(32-31bit)存储在内存的高地址处,低位字节(0-7bit)存储在内存的低地址处。

——现代PC大多采用小端字节序,所以小端字节序又被称为主机字节序。
大端字节序也称为网络字节序。

——
只有当传输跨越了多个字节的数据时才存在这个问题,比如TCP报文里的IP地址、端口,或者你的应用程序本身直接传数值。
(2)TCP统一规定使用大端方式传输数据,称为网络字节序。
(3)因此,inet_addr、htonl等这些函数就是把数据的本机字节序转化为网络字节序(即大端),这些函数内部都会自行判断本机字节序。

——为什么
同一个网络程序开发和跨平台的发展,也应采取措施,确保只有一个字节顺序或双方的解释是不一样的,因为发生错误。
——————————————————————————————————————————————————————

解决hash冲突的几种方式。

——开放式寻址法,开链法

有哪些方法清除cache中旧的数据。不太清楚,我扯到了操作系统中缺页中断的页面置换原理上,什么FIFO、最近最少使用、加权重等等。

——替换算法,LRU LFU FIFO 电梯调度等

进程和线程的区别。

多进程和多线程的使用场景。多进程答了一个分布式系统,多线程没答上来,后来问了才知道期望I/O密集型和CPU密集型这种答案。
——多线层是CPU密集型操作,例如图像处理,渲染的时候,不同维度由不同线程处理
——多进程是IO密集型操作,分布式系统中,不同的io可以使用不同的进程去执行。

死锁,如何解决死锁。解决死锁忘了,我扯到线程同步上来。

——死锁预防
——死锁监测,使用环路取监测。

了解哪些设计模式,装饰器模式是什么。

如何保证单例模式只有唯一实例,有哪些方法。
——static提供全局访问点
——const提供对象不能被修改

数据库设计三大范式。仅答了知道一、二、三范式,详细的没答。

——不会

SQL优化,有哪些优化方法。仅答了查询优化加索引。

——索引优化,

OSI七层模型和TCP/IP四层模型,每层列举2个协议。

TCP的三次握手和四次挥手。

C++中类成员的访问权限和继承权限问题。

——访问权限和继承权限不一样

C++中static关键字的作用。

——表示静态函数或者对象,不属于这个类对象,
——————————————————————————————————————————————————————

1.自我介绍

2.用过linux系统吗,哪种linux系统,版本呢?

——查看操作系统的版本,uname -a查看操作系统使用的内核,lsb_release -a查看当前是什么操作系统

3.linux基本命令。怎么查看IP;怎么给文件改名;怎么查看文件的权限;修改权限;怎么加执行权限;怎么查看当前系统的版本;怎么查看当前系统硬盘空间的总量与使用情况;怎么查看系统内存多少;怎么查看某个命令执行的时候需要链接哪些系统库;怎么给一个文件做一个软链接;

——查看ip,命令是ifconfig
——给文件改名,mv命令,类似$ mv test.txt wbk.txt
——查看文件的权限,ll,修改文件权限chmod,增加执行权限,chmod + x,x代表是执行权限
——怎么查看当前系统的版本,uname -a
——怎么查看当前硬盘的空间和使用情况,top
——怎么查看系统内存多少,top
——怎么查看某个命令执行的时候需要链接哪些系统库,ldd 某个命令或者进程
——怎么给文件做软连接,ln -s

4.vector与list的区别

——vector是连续的内存分配,list是分连续的内存分配
——vector支持随机访问,list类似链表只支持顺序访问
——vector有初始预分配空间,当超过这个空间的是会进行扩容操作,超过两倍的扩容操作,list是离散的内存分配,没哟扩容操作
——大量数据的插入,list要优于vector

5.怎么找某vector或者list的倒数第二个元素

——vector直接通过下标啊哦做,list需要通过迭代器形成快慢指针,从首节点开始遍历。

6.说一下map和set的区别

——map和set底层都是红黑树
——map是存储键值对的关系,key类似索引,value就是索引的关键值
——set就是关键词存储的集合,每个元素就是一个key,一般用于检查一个关键字是否在集合中

7.红黑树的原理

——红黑树是一种平衡二叉树,没有avltree那么严格的平衡条件,主要通过对节点进行红黑标志,并设定一定的红黑条件,以保证任意路径不会长于另外一条路径的两倍,
——红黑树对于不平衡或者插入的时间复杂度都是lgn

8.map怎么插入数据,有几种方式

——map插入数据,insert还有数组下标的方式

9.c++11在原来的版本上都加了哪些东西。

——auto for::容器,智能指针

10.智能指针,三种指针都介绍一下其特性,作用。

——智能指针主要有三种:unique_ptr,shared_ptr,weak_ptr
—unique_ptr:unique_ptr拒绝对其拷贝,也就是说同一时刻只能有一个unique_ptr指向给定对象
——shared_ptr: 一个引用计数智能指针,用于共享对象的所有权也就是说它允许多个指针指向同一个对象。
—weak_ptr:为了解决shared_ptr中出现的另一个问题,那就是当两个shared_ptr对象互相引用的时候,就会造成两个对象的引用计数无法到0,所以无法被释放。
—weak_ptr的设计方案就是使他可以从一个shared_ptr或者weak_ptr中构造,但是这样并不会使资源的引用计数增加。weak_ptr里面没有重载“*”“->”,所以并没有真正的获得资源的所有权,只能说是在观测资源的引用计数(通过use_count()和expired()函数),不过weak_ptr里有一个非常重要的成员函数lock(),它可以从shared_ptr中获得一个可用的shared_ptr对象,从而操作资源。当引用计数为空的时候,则会返回一个空指针。

11.进程怎么同步,线程怎么同步,要说全。

——线程同步,互斥锁,信号量,读写锁
——进程同步,互斥锁+信号量,生产者消费者问题

12.tcp与udp的区别,udp怎么实现多对多通信,问的很细,包括tcp的各种机制。

——面对流,一个是面对报文,一个是端对端,一个多对多通信

13.说一下快排

——————————————————————————————————————————————————————
算法:

二叉树遍历

——使用递归的话,前序中序后序都可以遍历,使用非递归的话,需要使用栈,栈的话前序中序比较简单,后序的话需要额外保存当前根节点

中序遍历的下一个节点(剑指offer原题,看了四五遍,还没记住,该打)
——如果没有给出指向父节点的指针,那么需要按照中序遍历一次二叉树,在遍历里面判断当前节点的下一个节点
——如果给出了指向父节点的指针,那么当前节点就有下面两种情况:

  1. 该节点存在右子节点,则下一个节点是右子树的最左节点。
  2. 该节点不存在右子节点,则下一个节点是该节点的第一个父子关系为左的祖先节点中的父节点, 因为如果遍历的节点是父节点的右节点说明父节点已遍历过了

翻转链表

——两种方法,一种是递归的方法,每次递归后一个节点,递归返回值是后一个节点,最后就是返回尾节点,返回之后需要对头结点做一个处理,一种是非递归的方法,三个指针,依次遍历更改指针的指向即可

二叉树深度

——两种方法,一种是递归的方法,当前节点的深度是左右子树深度最大值+1
——一种是层次遍历,每个层次就是深度+1
——————————————————————————————————————————————————————

1. 自我介绍(不多说了,基本都是一样)

2. 面向对象的三大特性

——面向对象的三种特性:抽象,继承,多态

3. cpp怎么实现多态的?

——静态多态(编译时):主要是有两种:函数重载和模板
——函数重载:就是具有相同的函数名但是有不同参数列表(参数列表包括参数的类型、参数的个数和参数的顺序,只要有一个不同就叫做参数列表不同)的函数,我们叫他们为函数重载。函数重载可以在编译时候就确定我们应该调用哪个函数,所谓我们称之为编译期的多态。
——模板:我们定义了模板函数在编译期就已经确定了T的数据类型,所以我们就可以正确的调用恰当的函数
动态多态(运行时):这个就是我们常见的虚函数的动态绑定

4. 如果有一个基类A有一个虚函数fun,子类B也有实现,基类A有一个函数init,里面调用了fun,A的构造函数有调用了init,那么init调用的是哪个fun?(多态实现机制的分析)

——init调用的是a的fun,因为a的构造的时候,b还没有构造,那么虚函数表中没有b对应重写的fun,所以init电泳的额就是a的fun。也就是a的虚表中找不到b中fun的函数地址

5. stl了解吗?vector底层实现怎么样?vector怎么扩容的?

——vector底层类似一个动态数组,首先会设定预分配大小,当预分配大小不够的时候,会进行扩容,扩容是从其他的内存空间在找原vector大小的两倍进行扩容,然后在把原大小迁移到新扩容空间上。

——————————————————————————————————————————————————————
C++基础
● 自我介绍

● 平时有用C++写过项目吗?(这里没让我展开说项目)

● 对C++的特性有什么了解

——抽象,继承,多态

● 对封装、继承、多态的具体理解

——封装就是讲数据的许多特性请求做一个封装,多外呈现调用接口的而部门
——继承就是继承子类继承父类的一些特性,可以直接拿来用
——多态就是调用同一个函数会有不同的执行状态

● public/protected/private的区别

——这些都是描述类的访问限制
——public就是自己的类对象可以访问
——private: 类的成员函数可以访问这些成员变量或成员函数
——protected: 类自己和子子孙孙可以访问

● 说一下三种方式继承对基类的访问权限

——publix对基类完全访问
——private基类都是私有化,只能通过成员函数来访问
——protected基类的公有成员和保护成员在派生类中的访问权限都会变为保护(protected)权限,私有成员在派生类中的访问权限仍然是私有(private)权限。

● 说说构造函数的执行顺序,析构函数呢

——构造函数构造顺序是从父类到子类
——析构函数刚好相反,是从子类到父类

● 说一下构造函数内部干了什么

——构造函数负责确定对象的初始状态以及分配必要的资源
——构造函数首先确定对象在内存中初始状态,并且对这个对象分布必要的一些内存资源

● 如何实现多态

——静态多态(编译时):主要是有两种:函数重载和模板
——函数重载:就是具有相同的函数名但是有不同参数列表(参数列表包括参数的类型、参数的个数和参数的顺序,只要有一个不同就叫做参数列表不同)的函数,我们叫他们为函数重载。函数重载可以在编译时候就确定我们应该调用哪个函数,所谓我们称之为编译期的多态。
——模板:我们定义了模板函数在编译期就已经确定了T的数据类型,所以我们就可以正确的调用恰当的函数
动态多态(运行时):这个就是我们常见的虚函数的动态绑定

● 构造函数和析构函数可以调用虚函数吗,为什么

——

● 构造函数跟虚构函数里面都可以调用虚函数,编译器不会报错。

C++ primer中说到最好别用
由于类的构造次序是由基类到派生类,所以在构造函数中调用虚函数,虚函数是不会呈现出多态的
类的析构是从派生类到基类,当调用继承层次中某一层次的类的析构函数时意味着其派生类部分已经析构掉,所以也不会呈现多态
因此如果在基类中声明的纯虚函数并且在基类的析构函数中调用之,编译器会发生错误。

● 析构函数一定要是虚函数吗,为什么

——在实现多态时,当用基类操作派生类,在析构时防止只析构基类而不析构派生类的状况发生。

● 怎么理解C++的面向对象和C的面向过程

——面向对象是首先抽象出各种对象(各种类),把数据和方法都封装在对象中(类),然后各个对象之间发生相互作用。面向过程是将问题分解成若干步骤(动作),每个步骤(动作)用一个函数来实现,在使用的时候,将数据传递给这些函数。

——

网上有一个典型的例子:把大象放入冰箱里面。

C++是这么做的:涉及到两个对象:冰箱和大象。三个动作:打开冰箱,放置大象,关闭冰箱。
首先定义一个冰箱类,他有打开的方法,放置的方法,关闭的方法。然后再定义一个大象类。接下来构建冰箱和大象的对象,然后冰箱对象调用打开门的方法,冰箱对象再调用放置大象对象的方法,最后冰箱对象关门。
当C是这么做的:首先打开冰箱门,然后把大象放入进去,最后关闭冰箱门。

● 可以介绍一下new的实现原理吗

——完成两件事,先底层调用malloc分了配内存,然后创建一个对象(调用构造函数)

● new和malloc的异同处

——new是调用了构造函数,malloc没有,只完成了内存的分配
——new会自动分配对象所占的内存空间大小,malloc需要自己计算出
——new会进行安全性检查,malloc不会

● C++怎么为各种变量分配内存空间的

——局部变量分配栈上面的空间
——new的对象分配堆上面的空间

● 引用了解吧,介绍一下

——引用就是对象的别名,必须初始化

● 拷贝构造函数内部做了什么,什么时候需要重写

——对象之间的拷贝定义,需要自己定义拷贝构造函数

● 初始化列表了解吗(以为是那个C11特性,没敢说)

——初始化列表按照对象声明的顺序进行,初始化时候即赋值,没有额外的拷贝过程

进程线程相关

● 了解过线程吗,谈一下进程和线程的联系和区别吧

● 对于共享的区域多个进程或线程一起访问会不会出问题,要怎么解决(同步和互斥)

● 进程通信有哪几种方式,介绍一下

网络(项目里有)

● Socket的流程是什么样的(服务端和客户端两个)

● 项目里用的什么协议(TCP)

● TCP和UDP的区别,优缺点

——1、TCP面向连接(如打电话要先拨号建立连接);UDP是无连接的,即发送数据之前不需要建立连接
2、TCP提供可靠的服务。也就是说,通过TCP连接传送的数据,无差错,不丢失,不重复,且按序到达;UDP尽最大努力交付,即不保证可靠交付
——
UDP具有较好的实时性,工作效率比TCP高,适用于对高速传输和实时性有较高的通信或广播通信。
4.每一条TCP连接只能是点到点的;UDP支持一对一,一对多,多对一和多对多的交互通信

数据结构

● 说说vector和list的不同,优缺点

● 平衡二叉树了解吗,说说它的特点,时间复杂度(logN)

● 说说二叉树的三种遍历(想让我写来着,没带纸笔,口述了算法思想和区别,递归和非递归)

● 图了解吗,说一说它的遍历(广度和深度)

回到C++

● 说说宏定义和const的区别

——宏定义是在预编译阶段完成的,不进行安全性检查,直接替换
——const编译阶段完成,运行时会进行安全性检查

● 宏定义和内联函数的区别

——内联函数可以作为某个类的成员函数,这样可以使用类的保护成员和私有成员。而当一个表达式涉及到类保护成员或私有成员时,宏就不能实现了(无法将this指针放在合适位置)。

● 内联函数的作用,和普通函数有什么区别

——
内联函数和普通函数的区别:
1、在编译过程中,内联函数在函数的调用点,把函数代码全部展开,所以没有标准函数的栈帧的开辟和回退。
(如果 调用函数的开销 > 函数执行的开销,那么就建议写为内联函数 )
调用的开销:函数的栈帧的开辟和回退
执行的开销:函数体内代码执行的开销
2、内联函数只在本文件可见,编译阶段就进行了替换,所以不产生符号,所以一般在头文件中定义,这样就可以在其它文件调用。普通函数产生符号,多个文件引用头文件,会产生符号重定义的错误。
.编译阶段不编译.h文件,只编译.c 或.cpp 文件

● C++有几种转换方法,简单介绍一下

——static_cast:静态强制转换,类似传统c语言里面括号的强制转换
——dynamic_cast:动态强制转换,主要应用于多态,父子类的类型转换,dynamic_cast和static_cast不同的是,它会检查类型转换是否
正确,不能转换,则会返回null,所以不算是强制转换。
——const_cast:取出const属性,比较简单,可以把const类型转换为非conse指针类型。

● 重载是什么,和重写有什么区别

方法重载是指同一个类中的多个方法具有相同的名字,但这些方法具有不同的参数列表,即参数的数量或参数类型不能完全相同
方法重写是存在子父类之间的,子类定义的方法与父类中的方法具有相同的方法名字,相同的参数表和相同的返回类型

猜你喜欢

转载自blog.csdn.net/u012414189/article/details/84946616