C++研发106面试题总结(三)
实现一个vector?是1.5还是2倍,各有什么优缺点?
1.5倍优势:可以重用之前分配但是释放的内存
2倍劣势:每次申请的内存都不可以重用
map底层用了什么?
红黑树
如果用map删除了一个元素,迭代器还能用吗?为什么?怎样做可以接着用?
能用,a.erase(it ++);因为是直接申请的内存,所以可以直接通过获取后续节点来处理
红黑树的特征是什么?
(1)根节点为黑色(2)一个节点为红色,子节点必定为黑色(3)从任意一点触发到达每一个叶子节点的黑色节点个数相同(4)每一个节点不是红色就是黑色(5)每一个叶子节点都是黑色
红黑树如何插入和删除的?
插入:
(1)如果父节点为黑色,直接插入不处理
(2)如果父节点为红色,叔叔节点为红色,则父节点和叔叔节点变为黑色,祖先节点变为红色,将节点操作转换为祖先节点
(3)如果当前节点为父亲节点的右节点,则以父亲结点为中心左旋操作
(4)如果当前节点为父亲节点的左节点,则父亲节点变为黑色,祖先节点变为红色,以祖先节点为中心右旋操作
删除:
(1)先按照排序二叉树的方法,删除当前节点,如果需要转移即转移到下一个节点
(2)当前节点,必定为这样的情况:没有左子树。
(3)删除为红色节点,不需要处理,直接按照删除二叉树节点一样
(4)如果兄弟节点为黑色,兄弟节点的两个子节点为黑色,则将兄弟节点变为红色,将着色转移到父亲节点
(5)如果兄弟节点为红色,将兄弟节点设为黑色,父亲结点设为红色节点,对父亲结点进行左旋操作
(6)如果兄弟节点为黑色,左孩子为红色,右孩子为黑色,对兄弟节点进行右旋操作
(7)如果兄弟节点为黑色,右孩子为红色,则将父亲节点的颜色赋值给兄弟节点,将父亲节点设置为黑色,将兄弟节点的右孩子设为黑色,对父亲节点进行左旋
红黑树和B+,B-的区别?
红黑树的深度比较大,而B+和B-的深度则相对要小一些,而B+较B-则将数据都保存在叶子节点,同时通过链表的形式将他们连接在一起。
线程同步几种方式?
互斥锁,信号量,临界区
手写strcpy,memcpy,memmove函数?
需要注意内存重叠问题
Do{}while(0)的用法有哪些?
(1)可以将语句当做一个独立的域(2)对于多语句可以正常的运行(3)可以有效的消除goto语句,达到跳转语句的效果
手写快排?时间复杂度?空间复杂度?能进行优化吗?还有吗?能进行尾递归优化吗?
最优时间复杂度:nlogn
最差时间复杂度:n^2
平均时间复杂度:nlogn
空间复杂度:logn -> n
优化:
(1)随机(2)三数取中(3)当排序达到一定长度时用插入排序(4)分隔一次后,将相同数据不处理(5)使用并行或者多线程(6)进行尾递归优化【即将logn降解为更低的复杂度】
线程池的作用是什么?
处理线程多并发,用一个数组保存线程,然后一直放着,如果没用就用条件变量让它休眠,如果加入一个新的任务就唤醒其中一个去执行这个任务。
Pthread_cond_signal和pthread_cond_broadcast的区别
Pthread_cond_signal表示唤醒睡眠线程中的一个【单播,可能按照优先级或者先来后到的原则】
Pthread_cond_boardcast表示唤醒所有睡眠线程【广播】
线程有几种状态?进程又有几种状态?
线程:
进程:
排序稳定的算法,你知道那些?
冒泡排序;插入排序;归并排序;基数排序
解决hash冲突的方法?
线性探测法;开链法;再哈希法;
C++分为内存分为哪几部分?
堆;栈;静态全局;常量;自由存储区
如果new申请内存失败了,如何去解决?如果让你实现一个new,你会怎么实现?
如果申请失败可以通过set_new_handler来进行处理。
实现:需要注意申请失败,如果相应的处理函数则调用,否则抛出bad_alloc异常
如何得到一个结构体内成员的偏移量?
进程与线程的区别?
(1)进程又自己的独立地址空间,线程没有
(2)进程是资源分配的最小单位,线程是CPU调度的最小单位
(3)进程和线程通信方式不同
(4)进程切换上下文开销大,线程开销小
(5)一个进程挂掉了不会影响其他进程,而线程挂掉了会影响其他线程
(6)对进程进程操作一般开销都比较大,对线程开销就小了
逐层打印二叉树?
用BFS队列
构造函数能不能虚函数?为什么?那拷贝构造函数能不能为虚函数?为什么?
不可以为虚函数,因为在调用构造函数时,虚表指针并没有在对象的内存空间中,必须要构造函数调用完成后才会形成虚表指针。
拷贝构造函数是构造函数所以理由同上。
析构函数能不能虚函数?为什么?
可以为析构函数,没有为什么
模板和实现可不可以不写在一个文件里面?为什么?
只能写在一个一个头文件中。
原因:多文件处理变为一个文件其实是通过链接器来实现的,所以如果用源文件来处理模板实现,会导致链接失效,最主要的原因还是在编译,编译器会暂时不处理模板类只有在实例化对象时才去处理,但是这就需要实现的代码了,如果放在其他文件的话,就会无法形成相应的类。
什么是RAII资源管理?
即资源获取就是初始化,利用对象生命周期来控制程序资源,简单来说就是通过局部对象来处理一些资源问题
为什么要字节对齐?
(1)有些特殊的CPU只能处理4倍开始的内存地址
(2)如果不是整倍数读取会导致读取多次
(3)数据总线为读取数据提供了基础
在成员函数中调用delete this会出现什么问题?对象还可以使用吗?
如果当前内存空间真正被释放了再次调用成员函数会报错,调用成员变量好像没有问题。
如果在构造函数中调用memset(this, 0, sizeof(*this))来初始化内存空间,有什么问题吗?
对于有虚函数和虚表存在的类,在进行memset后不能调用虚函数和虚基表继承而来的数据和函数
对一个数组而言,delete a和delete[] a有什么区别?为什么?
对于基础数据类型没有什么区别,对于对象delete值调用一次析构函数,delete[]才会析构所有的东西。
Dynamic_cast是如何实现运行时类型转换的?
如果有些虚函数的话,会到对应的虚表中的RTTI去查找对应的类型来判断可不可以进行相应的转换。
C语言调用C++语法函数怎么做?那C++调用C语法的函数怎么做?
使用extern “C”来产生C语言环境编译的程序供外部使用。
Extern “C”是什么意思?他有什么作用?
表示当前声明需要用C语言环境进行编译。
进程间的通信方式有哪些?线程间的通信方式呢?
进程:共享内存,消息队列传递,无名管道,有名管道,信号,套接字
线程:锁机制,信号量,信号
IO模型主要有哪些?
阻塞,非阻塞,IO多路复用,异步
阻塞和非阻塞?同步与异步的区别?
自己领悟
Select,poll和epoll的区别?为什么?
Select和poll缺点:(1)每次调用select都需要将fd集合从用户态拷贝到内核态(2)每一次调用select都需要在内核中遍历所有的fd(3)select支持的文件描述符太小,默认1024,poll没有限制
Epoll:使用红黑树来存储fd,同时每一次通过epoll__ctl来将fd加入内核中,同时通过双向列表来返回已经出发某一个事件的fd
手写如何通过一个结构体的成员变量得到一个结构体的地址?
Struct{char a[0];}的作用?有什么好处?
充当可变缓冲区的作用,同时char a[0]不占用内存空间。
如何判断两个浮点数相等?
需要考虑浮点误差
浮点数为什么会有误差?
因为二进制无法精准的表示十进制小数,0.3和0.2都无法完整的用二进制表示。