面试准备

这篇博客涵盖了C++面试中常见的知识点,包括C++基础问题、数据结构、计算机网络、数据库、操作系统、设计模式以及智力题等。重点讨论了TOPK问题的不同解决方案、链表环的检测、循环队列、各种排序算法、多态实现、内存管理和智能指针、数据结构(如二叉树、堆和栈)、数据库事务、MySQL特性、操作系统概念以及各种设计模式。此外,还涉及了一些智力题,如鸡蛋掉落问题和毒药问题。

C++编程

所有的代码在另一篇博文

TOPK问题(多种解法)

思路1:直接进行排序,输出最大的K个值即为TOPK(nlogn)
思路2:使用冒泡排序,K次冒泡之后,最大的即为数组后面K个元素(n*k)
思路3:维护一个大小为K小顶堆,将所给数组插入堆中,最后输出(nlog(k))

判断链表是否有环,寻找链表环的起点

思路1:快慢指针,快指针步进2,慢指针步进1,如果有环,这两个指针必然相遇,将其中一个指针回归到链表的起点,另一个指针从当前位置继续前进,步进都为1,下次相遇即为环的起点。

循环队列

具体看代码

快速排序(存在问题如何优化)、归并排序、堆排序(注意时空复杂度、稳定性)

  1. 数据量比较小的情况下,可以采用插入排序替换快速排序
  2. 将重复数据划分到一起,下一次递归时不对重复数据进行递归排序

反转一个链表

首先定义一个虚拟头节点指向原链表,避免进行边界判断,之后定义一个指针,指向头节点,每次循环,记录当前指针的下一个指针,然后将当前指针的下一个指向pre 再将pre赋值为当前指针,最后将当前指针赋值为记录下来的下一个指针

归并链表

首先定义一个虚拟头节点,然后循环判断当前传入的链表是否为空,不为空的话,就比较当前两个结点值的大小,小的链接到新的链表后面,循环结束,将还没有遍历完的链表直接链接在新链表后面即可

并查集

首先将变量的father结点全部初始化为当前下标,使用时,判断是否是同一个集合只用判断他的father结点是否相同,查找时,只用查找他的father结点即可。

二叉树的公共祖先

如果两个结点存在公共祖先,必然存在:

  1. 两个结点分别在该公共祖先的左右子树
  2. 两个结点都在公共祖先的某一个子树
  3. 两个结点某一个在公共祖先的位置
  4. 当前结点是公共祖先,另一个结点在该结点的子树,或另一个结点不在当前子树
  5. 当前子树不包含给出的两个结点

二叉树的遍历(非递归/递归)

递归较简单,前序按照根=》左==》右、中序按照左=》根=》右、后序按照左=》右=》根的顺序进行递归输出即可。
非递归需要借助栈来实现,

  1. 如果当前节点不为空,访问节点,并且把节点进栈,循环条件为栈不空,取出栈顶元素,将结点放入答案数组,右孩子不空,压入右孩子,左孩子不空,压入左孩子。继续循环
  2. 从当前子树根结点出发,一直往左走,把沿途结点全部入栈,直到最左边,对于最左边的结点来说,他没有左孩子,根据“左根右”的顺序,这时需要从堆栈中弹出这个结点,访问它(这里表现为加到res数组中)如果它有右孩子,就往右边走,然后对于这棵子树重复上面的操作。
  3. 和前序反过来即可

数组的全排列

从给定数组从前往后依次枚举,每次选择一个没有用过的数字,选好之后,将该数字的状态改为“已被使用”,同时将该数字放到path里面,然后进行递归,当递归返回时,不要忘记将该数的状态改回“未被使用”,并将该数从相应位置上删除。当递归遇到当前path.size()等于nums.size()时,将path加入答案数组。

N个骰子出现和为m的概率

投一个骰子时,所有的点数出现的概率均为1/6,多加一颗骰子,概率应该是比当前骰子少一颗的所有骰子点数出现的次数和 除以6n,即状态转移方程dp[i][j] = dp[i - 1][j - 6] + dp[i - 1][j - 5] + dp[i - 1][j - 4] + dp[i - 1][j - 3] + dp[i - 1][j - 2] + dp[i - 1][j - 1],最后的dp[n][m] /6n即为n个骰子出现和为m的概率。

两个链表交汇的位置

C++基础问题

详细讲解智能指针的思想,循环引用,unique_ptr的实现原理

动态内存管理通常会出现两种问题,第一就是忘记释放内存,造成内存泄漏,第二就是尚有指针引用内存的情况下就释放了他,就会产生引用非法内存的指针,为了更安全的管理内存,引入了智能指针(栈上的对象),智能指针包含三种(shared_ptr,unique_ptr,weak_ptr)shared_ptr允许多个指针指向同一个对象,unque_ptr独占所指的对象(类在离开作用域时会自动执行析构函数,为了实现独占,在类中把拷贝构造函数和拷贝赋值声明为private,这样就不可以对指针指向进行拷贝了。),weak_ptr之上shared_ptr所管理的对象。
可以认为shared_ptr 都有一个关联的计数器,无论何时我们拷贝shared_ptr 计数器都会递增,当我们给shared_ptr赋一个新值,或是shared_ptr被销毁(例如离开作用域),计数器就会递减,一旦一个shared_ptr的计数器变为0,他就会自动释放自己管理的对象

介绍一下野指针

指针变量刚被创建时不会自动变成NULL指针,所以没有初始化会变成野指针,指针指向的内存被释放了,但是指针本身没有置NULL,指针超过了变量的作用范围。

堆与栈的区别,两者申请内存的情况,如何分配内存

栈由编译器自动管理,堆由程序员管理,栈的内存空间一般较小,而堆内存空间比较大(32位系统4G),堆是动态分配的,而栈既可以动态分配也可以静态分配,静态分配是由编译器完成的

使用栈就像我们去饭馆里吃饭,只管点菜(发出申请)、付钱、和吃(使用),吃饱了就走,不必理会切菜、洗菜等准备工作和洗碗、刷锅等扫尾工作,他的好处是快捷,但是自由度小。使用堆就像是自己动手做喜欢吃的菜肴,比较麻烦,但是比较符合自己的口味,而且自由度大。

多态的实现,虚函数

多态分为静态多态和动态多态,静态多态就是重载,因为在编译器决议确定,所以称为静态多态,在编译时就可以确定函数地址,动态多态就是通过继承重写积累的虚函数实现的多态,运行时在虚函数表中寻找调用函数的地址。(对虚函数进行重写,实现多态)

重载的条件,重载在编译器下是什么样的

函数名相同、形参数量不同、形参类型不同、形参顺序不同
在编译器中,不同的重载函数对应的签名不同。基本映射关系为:返回类型+函数名+参数列表 例如 void print (int i) => _Z5printi

什么情况下会发生内存泄漏,怎么解决

  1. new delete 不匹配
  2. 使用delete没有加[]
  3. 当基类指针指向子类对象时,如果基类的析构对象不是虚函数,则子类的析构函数不会被调用

C++中的定义,指针,模板,多态,重载等(尤其是多态,给定一个程序,基类子类有不同实现,考虑输出结果,这一类的题目面试题也极为高频)

指针和引用的区别

  1. 指针是实打实的指向内存空间,引用不过是起了个别名
  2. 引用不能为空,但是指针可以为空
  3. 可以有多级指针,但是只能有一级引用
  4. 程序会为指针分配内存区域,而没有给引用分配内存区域

new和delete是如何实现的,new 与 malloc的异同处

new是c++关键字,底层实现是通过malloc来开辟内存,开辟完内存,可以进行初始化操作,delete其实是调用了其对应变量的析构函数,再销毁内存。
new是C++关键字而malloc是c函数,new以具体类型为单位进行内存分配而malloc以字节为单位进行内存分配,new在申请单个类型变量可进行初始化而malloc不具备内存初始化的特性。

C和C++的区别

c面向过程(分析出解决问题的步骤,然后把这些步骤一步一步的实现,使用时依次调用,不易维护,但是性能较好),C++面向对象(把问题分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描述某个事物在整个解决问题的步骤中的行为 ,易复用、易拓展、易维护,但是性能较差)

C++、Java的联系与区别,包括语言特性、垃圾回收、应用场景等(java的垃圾回收机制)
Struct和class的区别

  1. Struct默认是公有继承,而Class默认是私有继承
  2. Class中默认的成员访问权限是私有的,而Struct中则是公有的
  3. 如果Class和Struct中都定义了构造函数,就不能使用大括号对其进行初始化,若没有定义构造函数,Struct可以使用{}进行初始化,Class只有当所有的数据成员以及函数都为Public时才可以使用{}初始化。

define 和const的区别(编译阶段、安全性、内存占用等)

  1. define是在编译的预处理阶段起作用,而Const是在编译、运行的时候起作用。
  2. Const定义的常数是变量也带类型,而define定义的只是一个常数,不带类型
  3. define仅仅只是简单的字符串替换!!!注意这里经常会出错!
  4. define定义完之后,占用代码段空间,而const定义完之后占用数据段空间。

在C++中const和static的用法(定义,用途)
const和static在类中使用的注意事项(定义、初始化和使用)
C++中的const类成员函数(用法和意义)
计算下面几个类的大小
给一个代码,求输出结果
C++的STL介绍(这个系列也很重要,建议侯捷老师的这方面的书籍与视频),其中包括内存管理allocator,函数,实现机理,多线程实现等
STL源码中的hash表的实现
STL中unordered_map和map的区别
STL中vector的实现
vector使用的注意点及其原因,频繁对vector调用push_back()对性能的影响和原因。
C++中的重载和重写的区别:
C ++内存管理(热门问题)
介绍面向对象的三大特性,并且举例说明每一个。
多态的实现(和下个问题一起回答)
C++虚函数相关(虚函数表,虚函数指针),虚函数的实现原理(热门,重要)

如果类B继承了类A,那么我们知道生成B的实例对象时,会先调用A的构造函数,此时虚指针指向A的虚表,然后调用B的构造函数,此时虚指针指向B的虚表,所以当B的实例构造完成后,虚指针指向B的虚表。

实现编译器处理虚函数表应该如何处理
析构函数一般写成虚函数的原因
构造函数为什么一般不定义为虚函数
构造函数或者析构函数中调用虚函数会怎样
纯虚函数
静态绑定和动态绑定的介绍
引用是否能实现动态绑定,为什么引用可以实现
深拷贝和浅拷贝的区别(举例说明深拷贝的安全性)
对象复用的了解,零拷贝的了解
介绍C++所有的构造函数
什么情况下会调用拷贝构造函数(三种情况)
结构体内存对齐方式和为什么要进行内存对齐?
内存泄露的定义,如何检测与避免?
手写实现智能指针类(34-37我没遇见过)
调试程序的方法
遇到coredump要怎么调试
内存检查工具的了解
模板的用法与适用场景
成员初始化列表的概念,为什么用成员初始化列表会快一些(性能优势)?
用过C11吗,知道C11新特性吗?(有面试官建议熟悉C11)
C++的调用惯例(简单一点C++函数调用的压栈过程)
C++的四种强制转换
红黑树的了解(平衡树,二叉搜索树),使用场景
红黑树在STL上的应用
贪心算法和动态规划的区别
实现一个strcpy函数(或者memcpy),如果内存可能重叠呢
Bitmap的使用,存储和插入方法
1-n中有多少个1
字典树的理解以及在统计上的应用
一致性哈希
C++内存管理有哪些
指针和引用的区别
define和const有什么区别?
define和const分别在什么时候编译,哪个更安全
在类中,基类的析构函数为什么要设置成虚函数
虚函数的实现
面向对象的三个特性是什么?
详细介绍一下多态
如果我拿一个父类指针,指向一个子类的数组,要找这个数组的三个元素,应该怎么使用多态来实现
如果我用一个int类型的指针,指向一个vector< int >中的元素,会怎么样?
在vector里面有一个find函数,那如果我用find==-1,会发生什么(这个问题记不太清楚,只记得什么等于-1)
STL标准库
全局变量和局部的静态变量除了可见区域不同还有什么不同?
什么时候要有拷贝构造函数
C++里面的红黑树
C++类里面函数加const的原因和实现?能不能在函数前面加上static,为什么
讲讲static的用法

数据结构

map和unordered_map的底层实现
set,map和vector的插入复杂度
红黑树
能说说单源最短路径dijkstra算法吗
那dijkstra算法能够找到最短路径的原因是什么
说说最小生成树吧
贪心算法和动态规划有什么区别?

计算机网络

TCP三次握手、四次挥手

字段含义
序列号seq占4个字节,用来标记数据段的顺序。第一个字节的编号
确认号ack占4个字节,指期望接收到下一个字节的编号,报文段最后一个字节的编号+1即为确认号
确认ACK占1位,ACK = 1,确认号有效
同步SYNSYN = 1 表示这是一个连接请求,或连接接受报文
终止FIN用来释放一个连接

注意:ACK、SYN、FIN这些大写的单词表示标志位,其值要么是1,要么是0,ack,seq小写的单词表示序号

三次握手: 客户端发送Syn报文,并置发送序号为X,服务端接收到之后发送syn + ack报文,并置发送序号为Y,ack序号为X + 1,客户端收到服务端的报文后,发送ack报文,置发送序号为Z,ack序号为Y + 1。(假设当前有一段报文因网络原因滞留在了某个网络结点,延迟到某个时间点发送到了服务端,如果未采用三次握手,这时便会建立一个新的链接,但是由于客户端并没有发送建立链接的请求,于是当前服务端一直在等待客户端,浪费了资源)

四次挥手: 客户端发送Fin+Ack报文,并置发送序号为X,FIN为1,服务器关闭等待并发送报文,置ACK = 1,seq = Y, ack = X + 1,当服务器关闭连接之后,发送报文,FIN = 1,ACK = 1,Seq = Z , ack = X + 1,并等待进行最后确认,库户籍

如何实现可靠性,拥塞控制,数据包发生乱序如何恢复
DNS解析的过程,DNS是基于TCP还是UDP
HTTP长连接和短连接
TCP与UDP区别
TCP三次握手,如果失败会怎么样
TCP/IP分为几个层次,每个层里都有什么协议

TCP/IP是一个协议组,可分为四个层次:网络接口层、网络层、传输层和应用层。在网络层有IP协议、ICMP协议、ARP协议、RARP协议和BOOTP协议。在传输层有TCP与UDP协议。在应用层有HTTP、FTP、TELENT、SMTP、DNS等协议。

网络分为几层,每一层都是干什么的
TCP/IP协议及其编程:计算机网络基础,socket编程,其中子网划分,七层协议(例如交换机属于数据链路层一类题目),五层协议,协议名称及其作用,常用端口号,https1.0 1.1特性与区别,加密(对称,非对称),IO复用等
建立TCP服务器的各个系统调用
继上一题,说明socket网络编程有哪些系统调用?其中close是一次就能直接关闭的吗,半关闭状态是怎么产生的?
对路由协议的了解与介绍。内部网关协议IGP包括RIP,OSPF,和外部网关协议EGP和BGP.
路由协议所使用的算法。
TCP和UDP的区别

相同点:二者都是运输层的协议
不同点:TCP是面向连接的,UDP是面向无连接的,UDP程序结构较简单,TCP是面向字节流的,UDP是基于数据报的,TCP保证数据正确性,UDP可能丢包,TCP保证数据顺序,UDP不保证。

TCP和UDP相关的协议与端口号
TCP(UDP,IP)等首部的认识(http请求报文构成)
网页解析的过程与实现方法
在浏览器中输入URL后执行的全部过程(如www.baidu.com)
网络层分片的原因与具体实现
TCP的三次握手与四次挥手的详细介绍(TCP连接建立与断开是热门问题)
TCP握手以及每一次握手客户端和服务器端处于哪个状态(11种状态)
为什么使用三次握手,两次握手可不可以?
TIME_WAIT的意义(为什么要等于2MSL)
超时重传机制(不太高频)
TCP怎么保证可靠性(面向字节流,超时重传,应答机制,滑动窗口,拥塞控制,校验等)?
流量控制的介绍,采用滑动窗口会有什么问题(死锁可能,糊涂窗口综合征)?
tcp滑动窗口协议
拥塞控制和流量控制的区别
TCP拥塞控制,算法名字?(极其重要)
http协议与TCP联系
http请求报文的组成
http/1.0和http/1.1的区别
http的请求方法有哪些?get和post的区别。
http的状态码
http和https的区别,由http升级为https需要做哪些操作

http其实是一种无状态,无连接,基于请求与响应,应用层,基于TCP/IP协议传输数据的一个超文本传输协议,而https则是利用SSL/TLS建立安全信道,加密数据包的HTTP,HTTPS主要用来提供对网站服务器的身份认证,保护数据交换的隐私和完整性。

https的具体实现,怎么确保安全性

  1. 使用对称加密生成密钥对传输数据进行加密,然后再使用非对称加密的公钥对密钥进行加密,
  2. 通过单向hash函数对原文进行哈希,将需加密的明文摘要成一串固定长度的密文,不同的铭文摘要成的密文其结果总是不相同,同样的明文其摘要必定相同
  3. 数字签名技术,是公钥加密和数字摘要结合起来的产物,形成了实用的数字签名技术。

http中浏览器一个URL的流程,这个过程中浏览器做了什么,URL包括哪三个部分?大牛的博客

  1. 输入url后,按下回车键,浏览器将会查询该URL对应的DNS
  2. 查询到DNS之后,与服务器建立TCP连接
  3. 连接建立后,发送HTTP/HTTPS请求
  4. 服务器处理HTTP/HTTPS请求,并返回报文
  5. 浏览器接收到报文,并对页面进行渲染
  6. 断开HTTP/HTTPS

一个机器能够使用的端口号上限是多少,为什么?可以改变吗?那如果想要用的端口超过这个限制怎么办?

65535(216 - 1) 其中某些端口被系统占用,比如 1~1023

对称密码和非对称密码体系
数字证书的了解(高频)
客户端为什么信任第三方证书
RSA加密算法,MD5原理(MD5不算加密算法)
单条记录高并发访问的优化
介绍一下ping的过程,分别用到了哪些协议
TCP/IP的分片粘包过程
有没有抓过TCP包,描述一下
一个ip配置多个域名,靠什么识别?
服务器攻击(DDos攻击)
讲讲http的状态码,403,201什么意思

200 成功状态 201 服务器已经按照客户端的请求创建了一个新资源 204 服务器拒绝对put、post、delete、请求返回任何状态信息或表示 404 可以用来告诉客户端请求的URI为空
1XX用来通知,仅在与HTTP服务器沟通时使用 2XX表示操作成功了 3XX表示客户端需要做额外的工作才能获得需要的资源,4XX客户端错误 5XX服务端错误

讲讲ping的具体工作,用到哪些协议(这一块要熟一点,不要只记住用了哪些协议,要深挖怎么工作)
抓过TCP包吗?TCP包怎么构成
如果一个访问一个网站时间特别长,但是访问其他网站没有问题,可能是什么问题,怎么检查?那如果是别人访问这个网站都正常,但是你访问时间就是特别久,可能原因?

MySql

MySql如何实现事务,事务的隔离级别
关系型和非关系型数据库的区别(各自优点)
常用SQL语句(DDL,DML,DCL,TCL)
数据库中join的类型与区别(inner join, outer join, cross join, natural join, self join),注意适用场景和sql语句的编写
数据库的索引类型
聚集索引和非聚集索引的区别(叶节点存储内容)
唯一性索引和主码索引的区别
索引的优缺点,什么时候使用索引,什么时候不能使用索引(重点)
索引的底层实现(B+树,为何不采用红黑树,B树)
B树和B+树具体实现
索引最左前缀问题
Mysql的优化(高频,索引优化,性能优化)
数据库引擎介绍,innodb和myisam的特点与区别
数据库中事务的ACID(四大特性都要能够举例说明,理解透彻,比如原子性和一致性的关联,隔离性不好会出现的问题)
数据库隔离性设置不同会出现的问题(脏读、不可重复读、丢失修改、幻读)
数据库的隔离级别,mysql和Oracle的隔离级别分别是什么
数据库连接池的作用
Mysql的表空间方式,各自特点
分布式事务
数据库的范式
数据的锁的种类,加锁的方式
视图的作用与使用方法(如何删除等)
分库分表,主从复制,读写分离。(我不会,也没碰到过)
项目中哪里用到了数据库,怎么用的

操作系统

进程和线程的区别,进程调度算法,如何创建进程和线程,进程和线程的底层实现
进程与线程的区别
多线程实现方式,并行与并发
死锁可能产生的原因,条件变量怎么用,意义
进程通信方式(linux/windows,每种方式的特点)
线程通信(linux/windows)
进程与线程区别
页面置换策略(考察置换几次)
进/线程状态转换图
进程调度方式
死锁(必要条件,哲学家就餐,银行家,读者写者问题)
进程与线程的区别和联系
一个进程可以创建多少线程,和什么有关
一个程序从开始运行到结束的完整过程(四个过程)
进程通信方法(Linux和windows下),线程通信方法(Linux和windows下)
进程调度方法详细介绍
页面置换方法详细介绍
能否实现一个LRU算法
死锁的必要条件(怎么检测死锁,解决死锁问题)
哲学家就餐,银行家,读者写者,生产者消费者(怎么加锁解锁,伪代码)
海量数据的bitmap使用原理
布隆过滤器原理与优点
布隆过滤器处理大规模问题时的持久化,包括内存大小受限、磁盘换入换出问题
同步IO和异步IO
文件读写使用的系统调用
线程池的了解、优点、调度处理方式和保护任务队列的方式
怎么回收线程
僵尸进程问题
多线程同步(尤其是如果项目中用到了多线程,很大可能会结合讨论)
memcache了解
异常和中断的区别
一般情况下在Linux/windows平台下栈空间的大小

设计模式

工厂模式
单例模式
适配器模式
MVC设计模式
观察者模式

智力题

100层楼,只有2个鸡蛋,想要判断出那一层刚好让鸡蛋碎掉,给出策略(滴滴笔试中两个铁球跟这个是一类题)
毒药问题,n拼毒药,要快速找出哪一瓶有毒,需要几只小白鼠
博弈论问题
先手必胜策略问题:n本书,每次能够拿X-X本,怎么拿必胜
放n只蚂蚁在一条树枝上,蚂蚁与蚂蚁之间碰到就各自往反方向走,问总距离或者时间。
瓶子换饮料问题:多少个瓶子能够换1瓶饮料,问最多能喝几瓶
有100本书,每次拿1-5本书,要先手赢,怎么拿?
智力题:蚂蚁在树枝上的问题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值