xx公司后端开发一面

(1)C++ vector和list的区别?
(2)TCP为什么2次握手不行,TCP4次挥手的过程
(3)执行main函数之前和之后做了哪些工作?
(4)你在写程序的时候如果程序出现了死循环你怎么找到这个死循环?
(5)B+树的时间复杂度?为什么使用B+作为数据库的索引?
(6)Linux命令知多少?
(7)银行转账系统中如果A转账完成之后系统出错,系统怎么解决?
(8)MySQL引擎是什么?
(9)编程题:给你一个有序整数数组,数组中的数可以是正数、负数、零,请实现一个函数,这个函数返回一个整数:返回这个数组所有数的平方值中有多少种不同的取值。

(1)C++ vector和list的区别?
vector是动态数组实现的,一说到动态那肯定是在堆上分配空间的。如果容量超出原先设定的值,会以2倍扩增。性能上:因为是数组实现的,所以访问起来肯定是O(1)时间内访问。
因为是vector,所以会经常有插入和删除的操作:
如果在结尾插入并且空间够的情况下,很快,如果空间不够,则首先要进行扩容,扩容的过程中完成内存拷贝。在中间拷贝也是一样,如果空间足够大,只需要完成插入位置后的元素拷贝就行了,如果内存不够则也需要先进行扩容,然后进行拷贝。
如果删除的是结尾的元素的话很快就可以完成,如果是中间的元素那就需要拷贝了。
总体而言由于vector的特性原因,所以它很适合随机访问,并且插入删除在结尾部。
list是双向链表实现的,由于是双向链表,所以肯定也是在堆上分配空间的。
那自然插入和删除都是很容易的,因为双向链表实现的原理就是为了插入和删除。
具体的区别和联系:
都是在堆上分配空间
vector是基于动态数组实现的,list基于双向链表实现的
vector不便于中间插入和删除,list支持随机插入和删除
(2)TCP三次握手的过程:
A:我要跟你建立连接
B:好的,我准备好了,我可以和你建立连接
A:那我们开始吧
第三次握手是为了防止发送的报文未能及时到达服务端引发的问题,如果只有两次握手则在这种情况下会建立两个连接。
四次挥手的过程:
A:我要跟你断开连接了
B:你等一下,我还有东西没处理完
B:我处理完了,可以断开连接了
A;我断开连接了
四次挥手的原因是TCP通信本身是全双工的,所以每一方都要确认断开连接,如果只有三次握手的话,那第三次握手完,服务器端就不知道客户端是否收到了第三次握手的消息,这也是为什么客户端在第三次握手后会等待一个2MSL时间的原因,防止第四次握手的消息服务器没收到,如果服务器端没收到第四次握手的消息,服务器就会以为客户端没有收到第三次握手的消息,这时,服务器会在此给客户端发送第三次握手的消息。
(3)执行main函数之前和之后做了哪些工作?
main函数执行之前主要是系统的初始化资源:
  • 在栈区:设置栈指针
  • 在data段:初始化全局变量和静态变量
  • 在bss段:对未初始化的全局变量进行赋初值,bool是false,short,int,long 是0,指针是NULL
  • 将main函数的参数传到main函数里面
main函数执行完成之后并不一定意味着进程结束。
main函数执行完成之后:
  • 全局对象的析构函数会在main函数的执行后执行
  • 使用atexit注册的函数会在main函数执行之后执行
void fn1(void)
{
	printf("next.\n");
}

void fn2(void)
{
	printf("executed ");
}

void fn3(void)
{
	printf("is ");
}

void fn4(void)
{
	printf("This ");
}

int main(void)
{
	// 注册需要在 main 函数结束后执行的函数.  
	// 请注意它们的注册顺序和执行顺序
	// 在 main 函数结束后被调用,调用顺序与注册顺序相反。 先注册后执行。

	atexit(fn1);
	atexit(fn2);
	atexit(fn3);
	atexit(fn4);

	// 这条输出语句具有参照性,它可不是最后一句输出. 
	puts("This is executed first.");

	// EXIT_SUCCESS 代表 0,它定义在 stdlib.h 中. 
	// 我只是顺便提一下,也许你知道,但我担心你不知道,呵呵. 
	return EXIT_SUCCESS;
}
参考:https://blog.csdn.net/huang_xw/article/details/8542105
(4)你在写程序的时候如果程序出现了死循环你怎么找到这个死循环?
首先需要找可能出现死循环的进程,一个程序执行好久没有结果有可能有两个结果,第一:程序正在正常运行,但还没结果,第二:程序出现死循环
首先查看进程使用资源情况,如果内存占用正常,但是CPU占比接近100%,就说明可能出现死循环。
再使用pstack $pid查看进程栈,如果进程栈总是停留在一个位置,那这个位置就是死循环的位置,在文件里查看具体的代码就可以了。
(5)B+树的时间复杂度?为什么使用B+作为数据库的索引?
如果不考虑磁盘IO读取时间,M叉二叉树的时间复杂度是log(m,n);
因为B+树能够提供稳定高效的范围扫描,他的叶子节点是相互连接的,并且是排好序的,所以是为磁盘等外存设备设计的一种索引结构,而mysql的存储是存在外存上的。
B+树作为索引结构:还具有以下优点
  • 只有叶子节点才记录数据,非叶子节点只包含索引;所有非叶子节点也就是内部节点都只保存叶子节点最小值作为索引,那么这种结构的设计意味着内存中索引节点越多,他的整个IO次数就会下降
(6)Linux命令不懂,没回答上来
(7)银行转账系统中如果A转账完成之后系统出错,系统怎么解决?
数据库回滚
(8)MySQL引擎是什么?
InnoDB、Memory、MyIsAm、Merge存储引擎。
(9)编程题:给你一个有序整数数组,数组中的数可以是正数、负数、零,请实现一个函数,这个函数返回一个整数:返回这个数组所有数的平方值中有多少种不同的取值:
思路:这个题其实是leetcode有序数组的平方变过来的https://leetcode-cn.com/problems/squares-of-a-sorted-array/
其实思路也很简单,首先找数组中平方和最大的数,然后找次大的,一直找直到遍历完数组;
int findNumOfSquare(vector<int> &nums) {
	if (nums.size() < 2) { return nums.size(); }
	int cnt = 0;
	int i = 0, j = nums.size() - 1;
    
	while (i <= j) {
		int num1 = abs(nums[i]);
		int num2 = abs(nums[j]);
		if (num1 == num2) {//当前最大平方数为num1*num1或者num2*num2
            //去重
			while (i <= j && abs(nums[i]) == num1) { i++; }
			while (i <= j && abs(nums[j] == num2)) { j--; }
		}
		else if (num1 > num2) {//当前最大平方数为num1*num1
            //去重
			while (i <= j && abs(nums[i]) == num1) { i++; }
		}
		else {//当前最大平方数为num2*num2
            //去重
			while (i <= j && abs(nums[j]) == num2) { j--; }
		}
		cnt++;
	}
	return cnt;
}



#腾讯##面经##秋招##C++工程师#
全部评论
tql
3 回复 分享
发布于 2019-08-13 19:48
没怼项目吗
点赞 回复 分享
发布于 2019-08-13 20:26

相关推荐

拉丁是我干掉的:把上海理工大学改成北京理工大学。成功率增加200%
点赞 评论 收藏
分享
把球:这个听过,你加了就会发现是字节的hr
点赞 评论 收藏
分享
评论
6
97
分享
牛客网
牛客企业服务