记JD第一次面试

 

官网填错了邮箱地址,结果面试官还是很好的,打电话过来确认。

 

1.说下vector和list的底层实现 (一开始说它是底层就三个指针,然后说了动态扩容机制,面试官原来想知道它是什么存储的)

2.说下什么时候用vector和list(回答得不好,忘记说List得缺点了)

https://www.nowcoder.com/tutorial/93/2550f96bf7034399a3eb6dd3dafdce82 

3.如果要有什么得插入操作得话,那么应该使用vector还是list?

分情况谈论,考虑到是否需要查找,以及是否是尾部插入把,还有插入的空间大小是否是确定的

4.说下map的底层实现  

为什么有AVL树之后还会有红黑树呢?

5.怎么实现快速的查找操作(有什么结构)

6.unordered_map的底层实现,以及它的查找效率是多少呢?()

7.TCP与UDP的区别

 

8.UDP怎么实现一个可靠的传输呢?

主要是得借鉴TCP得可靠传输机制。

得类似于TCP协议得重传机制,首先建立一个UDP缓存区,用于存放数据包,然后UDP报文段的话也需要类似TCP一样进行一个切分,然后进行编号,每次传送的时候必须得收到对方得一个ACK.

https://blog.csdn.net/qq_41880190/article/details/89404864

 

9.进程与线程的区别

1.从创建,销毁,切换效率上看

2.通信机制不同

3.从稳定来看

 

10.堆与栈的区别?什么时候用堆,什么时候用栈(回答的不是很好,后面说了只要实现)

https://blog.51cto.com/jiuxiaotian/860844 

主要是分配效率那块没答上来,可以说动态内存分配有许多分配算法,不同人有不同的实现,像内存池这个东西,brk,mmap函数也可以扯上。

1)申请方式:

栈由系统自动分配和管理,堆由程序员手动分配和管理。

2)效率:

栈由系统分配,速度快,不会有内存碎片。

堆由程序员分配,速度较慢,可能由于操作不当产生内存碎片。

3)扩展方向

栈从高地址向低地址进行扩展,堆由低地址向高地址进行扩展。

4)程序局部变量是使用的栈空间,new/malloc动态申请的内存是堆空间,函数调用时会进行形参和返回值的压栈出栈,也是用的栈空间。

栈的效率高的原因:

栈是操作系统提供的数据结构,计算机底层对栈提供了一系列支持:分配专门的寄存器存储栈的地址,压栈和入栈有专门的指令执行;而堆是由C/C++函数库提供的,机制复杂,需要一些列分配内存、合并内存和释放内存的算法,因此效率较低。

 

11.算法题 (LRU,找到链表中间节点,快排)

 

总结:重点考察的还是数据结构以及算法的使用,面试完后得去看下STL相关的面试题以及使用某种结构的优缺点?

网上查找的STL面试题:

https://www.jianshu.com/p/a705f8b21283

https://blog.csdn.net/tianya_team/article/details/50753759

未看:

https://www.cnblogs.com/readlearn/p/10806408.html

https://www.cnblogs.com/lang5230/p/5556611.html

https://blog.csdn.net/zzb2019/article/details/81195294

https://blog.csdn.net/dreamispossible/article/details/89442263

 

 

 

 

 

 

 

 

 

 

 

 

 

二十七、hash_map和map的区别在哪里?

hash_map底层是散列的所以理论上操作的平均复杂度是常数时间,map底层是红黑树,理论上平均复杂度是O(logn),这里总结一下,选用map还是hash_map,关键是看关键字查询操作次数,以及你所需要保证的是查询总体时间还是单个查询的时间。如果是要很多次操作,要求其整体效率,那么使用hash_map,平均处理时间短。如果是少数次的操作,使用 hash_map可能造成不确定的O(N),那么使用平均处理时间相对较慢、单次处理时间恒定的map,考虑整体稳定性应该要高于整体效率,因为前提在操作次数较少。如果在一次流程中,使用hash_map的少数操作产生一个最坏情况O(N),那么hash_map的优势也因此丧尽了。

 

二十八、为何map和set不能像vector一样有个reserve函数来预分配数据?

map和set内部存储的已经不是元素本身了,而是包含元素的节点。也就是说map内部使用的Alloc并不是map声明的时候从参数中传入的Alloc。例如:
map, Alloc > intmap;
这时候在intmap中使用的allocator并不是Alloc, 而是通过了转换的Alloc,具体转换的方法时在内部通过
Alloc::rebind重新定义了新的节点分配器,详细的实现参看彻底学习STL中的Allocator。
其实你就记住一点,在map和set里面的分配器已经发生了变化,reserve方法你就不要奢望了。
 

 

十七、vector中erase方法与algorithn中的remove方法区别

vector中erase方法真正删除了元素,迭代器不能访问了

remove只是简单地将元素移到了容器的最后面,迭代器还是可以访问到。因为algorithm通过迭代器进行操作,不知道容器的内部结构,所以无法进行真正的删除。
 

十五、STL对于小内存块请求与释放的处理

STL考虑到小型内存区块的碎片问题,设计了双层级配置器,第一级配置直接使用malloc()和free();第二级配置器则视情况采用不同的策略,当配置区大于128bytes时,直接调用第一级配置器;当配置区块小于128bytes时,便不借助第一级配置器,而使用一个memory pool来实现。究竟是使用第一级配置器还是第二级配置器,由一个宏定义来控制。SGI STL中默认使用第二级配置器。
二级配置器会将任何小额区块的内存需求量上调至8的倍数,(例如需求是30bytes,则自动调整为32bytes),并且在它内部会维护16个free-list, 各自管理大小分别为8, 16, 24,…,128bytes的小额区块,这样当有小额内存配置需求时,直接从对应的free list中拔出对应大小的内存(8的倍数);当客户端归还内存时,将根据归还内存块的大小,将需要归还的内存插入到对应free list的最顶端。
小结:
STL中的内存分配器实际上是基于空闲列表(free list)的分配策略,最主要的特点是通过组织16个空闲列表,对小对象的分配做了优化。
1)小对象的快速分配和释放。当一次性预先分配好一块固定大小的内存池后,对小于128字节的小块内存分配和释放的操作只是一些基本的指针操作,相比于直接调用malloc/free,开销小。
2)避免内存碎片的产生。零乱的内存碎片不仅会浪费内存空间,而且会给OS的内存管理造成压力。
3)尽可能最大化内存的利用率。当内存池尚有的空闲区域不足以分配所需的大小时,分配算法会将其链入到对应的空闲列表中,然后会尝试从空闲列表中寻找是否有合适大小的区域,
但是,这种内存分配器局限于STL容器中使用,并不适合一个通用的内存分配。因为它要求在释放一个内存块时,必须提供这个内存块的大小,以便确定回收到哪个free list中,而STL容器是知道它所需分配的对象大小的,比如上述:
stl::vector array;
array是知道它需要分配的对象大小为sizeof(int)。一个通用的内存分配器是不需要知道待释放内存的大小的,类似于free(p)。
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值