提问环节
项目
Q1:具体调了那些参数?
Q2:具体的IO是什么?对于不同客户,IO是不一样的,是怎么处理的呢?
Q3:根据我的经验,实际的现场IO是很复杂的,不是某个单一的IO,你们是怎么考虑的呢?
Q4:能谈谈你实际过程中,对哪个具体参数的调整经验吗?
个人感受:可能面试官本身就是做存储的,所以项目问的很细,直击痛点,怼了四十分钟。。。
基础
Q1: 下面代码输出什么?
class A {
public:
virtual int get_v() {return v;}
private:
int v = 10;
};
int main() {
A* a = new A();
memset(a, 0, sizeof(A));
std:: cout << a->get_v() << std::endl;
delete a;
};
答案:虚函数的调用,都是通过对象的ptr
(指向虚函数表,虚函数表存在只读数据段.rodata
,也就是常量区;虚函数位于代码段.text
,也就是代码区)指针,所以memset
会也会将这个ptr
指针初始化为0,导致后面的调用出错。所以,memset
函数一般用来初始化基本数据类型的数组,类中含有C++类型的对象(string, list, set, map等)时,千万不要使用memset
进行初始化,因为会破坏对象的内存,可用构造函数来实现。类中含有虚函数,也不能用memset
,会报错!
Q2:下面代码执行后,v的值是多少?
void f(uint16_t* addr) { (*addr) = 10; }
uint32_t v; f(&v);
答案:会报错,&v是(uint32_t * )类型,addr 是 (uint16_t * )类型。除非强制类型转化,附上测试代码
#include <bits/stdc++.h>
using namespace std;
class A {
public:
virtual int get_v() {return v;}
private:
int v = 10;
};
void f(uint16_t* addr) {
(*addr) = 10;
}
int main() {
// T1
// A* a = new A();
// memset(a, 0, sizeof(A));
// cout << a -> get_v() << endl; // 报错
// delete a;
// T2
uint32_t v = 0;
// uint16_t* p = &v; // 报错
// uint16_t* p = (uint16_t*)&v; // 强制转化
// *(p) = 10;
// cout << (*p) << endl; // 输出10
// f(&v); // 报错
f((uint16_t*)&v); // 强制类型转化
cout << v << endl; // 输出10
return 0;
};
Q3:
- 平时写题、比赛时会用到树结构吗?
- 会,会用二叉树,但是我们一般不用链表实现,而是用数组模拟,例如父节点存在下标为 x 的位置,那么它的左右孩子分别为 (2 * x) 和 (2 * x + 1),这样虽然会造成内存使用不充分,但是操作起来,比链表方便
- 那如果需要对树进行增加、删除节点呢
- 我们一般用STL容器的 set map,它们的底层都是树结构,一般都可以满足我们的需求
- 那你们由考虑STL容器效率吗,有没有效率不够的时候,举个例子呢?
- 额,一般不会,没怎么遇到过。。。。
Coding
Q:在不开O(n)空间的前提下,实现如下转换:abbceddddaaaaaaaaaaaakaa
-> ab2ced4a12ka2
A:
#include <bits/stdc++.h>
using namespace std;
class Solution {
public:
void convert(string& s, int& slow, int cnt) {
vector<char> v;
while (cnt) {
int tmp = cnt % 10;
v.push_back(tmp);
cnt /= 10;
}
for (int i = v.size() - 1; i >= 0; --i) {
s[slow++] = char(v[i] + '0');
}
}
void solve(string& s) {
int fast = 0, slow = 0; // fast 为旧字符串的遍历位置, slow 为新字符串的当前更新位置
int cnt = 0; // 记录重复数字个数
for (fast = 0; fast < s.size(); ++fast) {
if (fast > 0 && s[fast] != s[fast - 1]) {
s[slow++] = s[fast - 1];
// !!!注意坑 不能直接 s[slow++] = char(cnt + '0'), cnt 可能大于9
if (cnt > 1) { // 重复字符
convert(s, slow, cnt);
}
cnt = 1;
} else {
cnt++;
}
}
// 尾部处理
// !!对于 for 处理,最后一定得考虑尾部处理!!!
// 面试时,调试了半天。。。
s[slow++] = s[fast - 1];
if (cnt > 1) { // 重复字符
convert(s, slow, cnt);
}
// 删除多余字符
s.erase(slow, s.size());
}
};
int main() {
Solution solution;
string s = "abbceddddaaaaaaaaaaaakaa";
solution.solve(s);
cout << s << endl;
return 0;
}
提问
Q:对于网上一些用C/C++实现一个数据库、聊天室这样的项目,您们看到是怎样的感受?对实际工作有帮助吗?
A:如果你深入跟进去了,对涉及到的相关知识去进一步学习,那么肯定是有作用的,但是如果只是过一遍,其实效果不大,与实际工作差别挺大的。
面试官评价
你的项目,其实还是浮在上面,对参数去调参,但是没有对参数到底如何影响性能的,做进一步了解,算一般吧。
基础方面,不是很差,也不是很好,中等水平。
你的Coding还是很不错的,无论是思路,还是调试的敏捷程度,都是很不错的,但是对比工程上的代码,有些地方还是比较粗糙的。当然了,我们对应届生的要求,不能和社招相同。整体我这边会给你通过的。