腾讯云智 后端开发-C++ 一面
1. 自我介绍
这个看个人具体情况了
2. 实习中测试业务介绍
在实习期间,我xxxx 巴拉巴拉说一堆, 如果没有也不会问这条的 看个人情况
3. 计算机网络分层介绍
常见的网络分层模型有OSI七层模型与TCP/IP模型。OSI模型自下而上依次为物理层、数据链路层、网络层、传输层、会话层、表示层与应用层;TCP/IP模型通常划分为网络接口层、网络层、传输层及应用层。分层设计降低了系统复杂性,各层独立实现特定功能,方便维护与升级。
4. TCP相较于UDP是可靠的原因
TCP是面向连接的协议,在数据传输前必须建立可靠连接。它通过序列号、确认应答(ACK)、重传机制、流量控制和拥塞控制等手段来保证数据的有序、完整传送,而UDP则没有这些机制,传输过程中可能出现数据丢失及乱序的情况。
5. TCP除了握手还保证数据可靠的机制
TCP通过以下机制确保数据可靠交付:
- 重传机制:超时未确认的数据包会被重传。
- 序列号与确认号:确保数据包按正确顺序到达。
- 滑动窗口:控制未确认数据量,实现流量控制。
- 拥塞控制:根据网络状况动态调整传输速率。
- 校验和:检测数据在传输过程中的错误。
6. TCP三次握手机制过程
- 客户端发送带SYN标志的数据包,并选择初始序列号,向服务端请求建立连接。
- 服务端收到后回复带SYN和ACK标志的数据包,确认客户端请求并发送自己的初始序列号。
- 客户端收到后再发送ACK数据包,确认服务端的响应,连接建立成功。
7. 为什么三次握手中需要第三步
第三步保证客户端成功收到服务端的SYN-ACK,确保双方初始序号同步并建立一个稳定、双向确认的连接,从而防止网络延迟或丢包导致的不一致情况。
8. 计算机网络中滑动窗口及其目的
滑动窗口是一种流量控制机制,允许发送方在未收到确认数据前连续发送多个数据包,从而提高数据传输效率,同时防止接收方被过量数据淹没。其目的是在保证传输效率的同时,确保数据传输的可靠性。
9. 算法层面,滑动窗口一般怎么实现
利用环形缓冲区或队列保存未确认数据,维护窗口的起始和结束指针。收到ACK后窗口前移并释放已确认数据,若超时则重传窗口内未确认的数据,同时结合拥塞控制动态调整窗口大小,保证传输效率与可靠性。
10. 判断两个单向链表是否交叉
方法一:计算链表长度法
- 分别遍历两个链表计算长度。
- 比较两个链表的尾节点,若不同则不相交。
- 较长链表先走长度差步数,再同时遍历,比较节点指针是否相同,相同处即为交点。
方法二:双指针法
- 定义两个指针分别指向两个链表头。
- 当一个指针走到末尾时切换到另一个链表头继续遍历。
- 最终两个指针若相遇,则该处即为交点;若均为NULL,则无交点。
下面是C++代码实现示例:
#include <iostream>
using namespace std;
struct ListNode {
int val;
ListNode *next;
ListNode(int x) : val(x), next(nullptr) { }
};
// 方法一:计算链表长度法
int getLength(ListNode* head) {
int len = 0;
while (head) {
++len;
head = head->next;
}
return len;
}
ListNode* findIntersection_LengthMethod(ListNode* headA, ListNode* headB) {
int lenA = getLength(headA);
int lenB = getLength(headB);
// 让较长链表先走差值步数
while (lenA > lenB) {
headA = headA->next;
--lenA;
}
while (lenB > lenA) {
headB = headB->next;
--lenB;
}
// 同时遍历寻找交点
while (headA && headB) {
if (headA == headB) return headA;
headA = headA->next;
headB = headB->next;
}
return nullptr;
}
// 方法二:双指针法
ListNode* findIntersection_DoublePointer(ListNode* headA, ListNode* headB) {
if (!headA || !headB) return nullptr;
ListNode* a = headA;
ListNode* b = headB;
while (a != b) {
a = (a) ? a->next : headB;
b = (b) ? b->next : headA;
}
return a; // 或 b
}
int main() {
// 构造交叉链表
// 交叉部分
ListNode* common = new ListNode(8);
common->next = new ListNode(10);
// 链表A: 3 -> 7 -> 8 -> 10
ListNode* headA = new ListNode(3);
headA->next = new ListNode(7);
headA->next->next = common;
// 链表B: 99 -> 1 -> 8 -> 10
ListNode* headB = new ListNode(99);
headB->next = new ListNode(1);
headB->next->next = common;
ListNode* intersection1 = findIntersection_LengthMethod(headA, headB);
ListNode* intersection2 = findIntersection_DoublePointer(headA, headB);
if (intersection1)
cout << "方法一交叉点数值为: " << intersection1->val << endl;
else
cout << "方法一无交叉" << endl;
if (intersection2)
cout << "方法二交叉点数值为: " << intersection2->val << endl;
else
cout << "方法二无交叉" << endl;
// 释放内存(此处简略处理)
delete headA->next; // 删除 7 节点
delete headA; // 删除 3 节点
delete headB->next; // 删除 1 节点
delete headB; // 删除 99 节点
delete common->next; // 删除 10 节点
delete common; // 删除 8 节点
return 0;
}
C++面试总结 文章被收录于专栏
本专栏系统梳理C++面试高频考点,从基础语法、内存管理、STL与设计模式,到操作系统与项目实战,结合真实面试题深度解析,帮助开发者高效查漏补缺,提升技术理解与面试通过率,打造扎实的C++工程能力。
查看14道真题和解析