字节跳动 Pangle 后台开发一二面:C++ 基础、MVCC 与合并 K 个有序链表
- 轮次
- 多轮面试合集
- 时间
- 2026-09
- 来源
- 牛客网
《面试题目》
一面
- C++ 指针、引用的区别?
- C++ final 标识符的作用?
- malloc 怎么分配内存的,通常有哪些方法?
- MySQL MVCC 的作用,怎么实现的?
- RC、RR 隔离级别的区别,怎么实现的?
- 三次握手四次挥手,其他次数为什么不行?
- SQL:选出表中成绩第二高的学生
- 算法:多个有序链表合并(IDE 里用不了 priority_queue,只能自己手写堆)
二面
- C++ 各个智能指针,把知道的各个方面都说一下
- 内核线程和用户线程的区别?
- 操作系统怎么进入内核态的,进入过程中做了什么?
- Kafka 的整体架构、消息确认机制?
- skill 和 MCP 的区别?
- 80% 概率生女孩、20% 概率生男孩,每个家庭都生到女孩才停止,最后男女孩比例多少?
《参考解析》
-
指针与引用这题要答到「能不能改、能不能为空、有没有地址」:引用必须初始化且绑定后不可改绑、没有独立地址(取地址拿到的是被引用对象)、不能为空;指针可重新赋值、可为空、可做算术。再往下延一层才有区分度:引用在编译期通常靠指针实现,函数传引用避免了拷贝与空值判断;const 引用能延长临时对象生命周期;返回局部变量的引用/指针都是悬垂。
-
malloc 的分配路径要能讲到系统调用层:小块内存由分配器从堆(
brk/sbrk扩展的连续区域)里切,空闲块用 bin/空闲链表管理,切割与合并决定碎片程度;大块直接mmap一块独立区域、释放时归还给内核,避免污染堆。多线程下每个线程有自己的 arena,减少锁竞争;free必须传原始指针、不能释放栈或常量区内存。能顺口区分 malloc/free 与 new/delete(构造析构、类型安全、失败抛异常)是基本要求。 -
MVCC 与隔离级别是同一道题的两面:MVCC 靠「隐藏版本信息 + 一致性读视图」实现——InnoDB 每行带事务版本号,回滚段里留旧版本,读的时候按 Read View 判断该版本对自己是否可见;RC 每次查询都生成新的 Read View,所以能看到别人已提交的新数据(不可重复读),RR 在事务开始时生成一次并复用,因此可重复读。要顺带说清快照读与当前读(
select ... for update、update)的区别,以及 RR 下靠间隙锁解决部分幻读。 -
三次握手/四次挥手的关键是「为什么不能少」:三次是因为双方都要确认「自己的发送和对方的接收都正常」,两次握手无法让服务端确认客户端收到了自己的 SYN-ACK,且会导致历史连接被误建;四次挥手是因为 TCP 全双工,一方 FIN 只表示不再发送、对方仍可能有数据要发,所以 ACK 与自己的 FIN 不能合并。补一句 TIME_WAIT 的意义(保证最后的 ACK 可靠到达、让旧报文消亡)和大量 TIME_WAIT 的常见处置。
-
第二高成绩的 SQL 有两种写法,边界要主动说:最直观的是
select max(score) from t where score < (select max(score) from t);要排名就用窗口函数dense_rank() over (order by score desc)取等于 2 的行(dense_rank并列同名次,row_number不会,问清需求再选)。边界必须提:没有第二高时用max写法会返回 NULL,用limit 1 offset 1在并列时会错。答题时先问「并列算第几」「是否要返回学生信息」。 -
合并 K 个有序链表考的是「手写堆」而不是背模板:标准解法是小顶堆维护每个链表当前头节点,每次弹出最小者接到结果尾部、再把该链表的下一个压入,复杂度 O(N log K)。面试官禁用
priority_queue就是在看你能否手写下沉/上浮——push末尾插入后上浮,pop用末尾元素替换堆顶后下沉。另一条路是分治两两合并(O(N log K)、常数更小、不用写堆),并把空链表、单个链表、链表长度为 0 的边界处理干净。 -
生男生女的比例题按期望算,答案是 1:4(男:女):每户最后一定生一个女孩,所以每户女孩的期望是 1;男孩是女孩之前的所有失败次数,服从参数 p = 0.8 的几何分布,期望 (1−p)/p = 0.25。两者相除,男孩:女孩 = 1:4。这类题的通用套路是「先写出该户各类人数的期望,再问总体的比」——注意别用「每次出生男女独立、所以总体 1:1」这种直觉答案,停生规则确实会改变比例;如果规则改成「生到男孩才停」结论就反过来,答题时说清前提更稳。