美文网首页
面试基础知识

面试基础知识

作者: 什锦甜 | 来源:发表于2018-08-06 18:14 被阅读44次

    stl容器总结:

    • 各种容器的元素在内存中的储存方式
    1. vector(向量):相当于数组,但其大小可以不预先指定,并且自动扩展。它可以像数组一样被操作,
      由于它的特性我们完全可以将vector 看作动态数组。在创建一个vector 后,它会自动在内存中分配一块连续的
      内存空间进行数据存储,初始的空间大小可以预先指定也可以由vector 默认指定,这个大小即capacity()函数的返回值。当存储的数据超过分配的空间时vector 会重新分配一块内存块,但这样的分配是很耗时的,效率非常低。

    2. deque(队列):它不像vector 把所有的对象保存在一块连续的内存块,而是采用多个连续的存储块,并且在一个映射结构中保存对这些块及其顺序的跟踪。向deque 两端添加或删除元素的开销很小,它不需要重新分配空间。

    3. list(列表):是一个线性链表结构,它的数据由若干个节点构成,每一个节点都包括一个信息块(即实际存储的数据)、一个前驱指针和一个后驱指针。它无需分配指定的内存大小且可以任意伸缩,这是因为它存储在非连续的内存空间中,并且由指针将有序的元素链接起来。

    4. set, multiset, map, multimap 是一种非线性的树结构,具体的说采用的是一种比较高效的特殊的平衡检索二叉树—— 红黑树结构。

    • 各种容器优劣分析
    1. Vector:
    • 优点:
      A、支持随机访问,访问效率高和方便,它像数组一样被访问,即支持[ ] 操作符和vector.at()。
      B、节省空间,因为它是连续存储,在存储数据的区域都是没有被浪费的,但是要明确一点vector 大多情况下并不是满存的,在未存储的区域实际是浪费的。
    • 缺点:
      A、在内部进行插入、删除操作效率非常低。
      B、只能在vector 的最后进行push 和pop ,不能在vector 的头进行push 和pop 。
      C、 当动态添加的数据超过vector 默认分配的大小时要进行内存的重新分配、拷贝与释放,这个操作非常消耗能。
    1. List:
    • 优点:不使用连续的内存空间这样可以随意地进行动态操作,插入、删除操作效率高;
    • 缺点:
      A、不能进行内部的随机访问,即不支持[ ] 操作符和vector.at(),访问效率低。
      B、相对于verctor 占用更多的内存。
    1. Deque:
    • 优点:
      A、支持随机访问,方便,即支持[ ] 操作符和vector.at() ,但性能没有vector 好;
      B、可以在两端进行push 、pop 。
      缺点:在内部进行插入、删除操作效率低。

    综合:
    vector 的查询性能最好,并且在末端增加数据也很好,除非它重新申请内存段;适合高效地随机存储。
    list 是一个链表,任何一个元素都可以是不连续的,但它都有两个指向上一元素和下一元素的指针。所以它对插入、删除元素性能是最好的,而查询性能非常差;适合 大量地插入和删除操作而不关心随机存取的需求。
    deque 是介于两者之间,它兼顾了数组和链表的优点,它是分块的链表和多个数组的联合。所以它有被list 好的查询性能,有被vector 好的插入、删除性能。 如果你需要随即存取又关心两端数据的插入和删除,那么deque 是最佳之选。

    1. 关联容器的特点是明显的,相对于顺序容器,有以下几个主要特点:
      A. 其内部实现是采用非线性的二叉树结构,具体的说是红黑树的结构原理实现的;
      B. set 和map 保证了元素的唯一性,mulset 和mulmap 扩展了这一属性,可以允许元素不唯一;
      C. 元素是有序的集合,默认在插入的时候按升序排列。

    基于以上特点
    A. 关联容器对元素的插入和删除操作比vector 要快,因为vector 是顺序存储,而关联容器是链式存储;比list 要慢,是因为即使它们同是链式结构,但list 是线性的,而关联容器是二叉树结构,其改变一个元素涉及到其它元素的变动比list 要多,并且它是排序的,每次插入和删除都需要对元素重新排序;

    B. 关联容器对元素的检索操作比vector 慢,但是比list 要快很多。vector 是顺序的连续存储,当然是比不上的,但相对链式的list 要快很多是因为list 是逐个搜索,它搜索的时间是跟容器的大小成正比,而关联容器 查找的复杂度基本是Log(N) ,比如如果有1000 个记录,最多查找10 次,1,000,000 个记录,最多查找20 次。容器越大,关联容器相对list 的优越性就越能体现;

    C. 在使用上set 区别于vector,deque,list 的最大特点就是set 是内部排序的,这在查询上虽然逊色于vector ,但是却大大的强于list 。

    D. 在使用上map 的功能是不可取代的,它保存了“键- 值”关系的数据,而这种键值关系采用了类数组的方式。数组是用数字类型的下标来索引元素的位置,而map 是用字符型关键字来索引元素的位置。在使用上map 也提供了一种类数组操作的方式,即它可以通过下标来检索数据,这是其他容器做不到的,当然也包括set 。(STL 中只有vector 和map 可以通过类数组的方式操作元素,即如同ele[1] 方式)。

    • stl用过哪些容器?有没有看过源码?比如vector原理有没有了解,vector插入元素会发生什么?(提到allocator原理,追问二级分配器的内存池有几个空闲链表)

    unordered_map和map区别,如何避免哈希冲突?

    • 运行效率方面:unordered_map最高,而map效率较低但 提供了稳定效率和有序的序列。
    • 占用内存方面:map内存占用略低,unordered_map内存占用略高,而且是线性成比例的。
    • 需要无序容器,快速查找删除,不担心略高的内存时用unordered_map;有序容器稳定查找删除效率,内存很在意时候用map。
    • map的内部实现是二叉平衡树(红黑树);hash_map内部是一个hash_table一般是由一个大vector,vector元素节点可挂接链表来解决冲突,来实现.

    hash_map其插入过程是:
    1)得到key
    2)通过hash函数得到hash值
    3)得到桶号(一般都为hash值对桶数求模)
    4)存放key和value在桶内。

    其取值过程是:
    1)得到key
    2)通过hash函数得到hash值
    3)得到桶号(一般都为hash值对桶数求模)
    4)比较桶的内部元素是否与key相等,若都不相等,则没有找到。
    5)取出相等的记录的value。

    避免哈希冲突的四种方法
    1)链地址法:是将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。 适合频繁进行插入和删除的情况。
    2)开放地址法:当发生地址冲突时,按照某种方法继续探测哈希表中的其他存储单元,直到找到空位置为止。
    3)再哈希法:这种方法同样是按照按某种方法探测哈希表中的其他存储单元,直到找到空位置为止。
    4)建立公共溢出区:将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。

    • 熟悉linux的IO模型么?同步异步有何区别?同步和阻塞一回事么

    • 数据库索引是怎么回事?用的啥数据结构?

    • 操作系统怎么样,比如调度算法有没有了解?(说了解linux,重点讲了CFS调度算法)

    • 进程间通信方式有哪些?熟悉哪个?

    • 软件开发会经常用到多线程吧?你说说自旋锁怎么回事?和互斥锁有啥区别(睡眠锁与非睡眠锁)

    • 熟悉哪些算法?说一下经典的排序算法?归并的时间和空间复杂度

    • Hashmap的原理,Hashmap为什么大小是2的幂次

    • 介绍一下红黑树

    • Arraylist的原理

    • Arraylist的扩容机制

    • 为什么arraylist扩容是1.5倍

    • 场景题:设计判断论文抄袭的系统

    • 堆排序的原理

    基本算法
    Linux命令的使用
    操作系统(着重)
    网络(着重)
    数据库
    编译技术
    分布式

    Linux使用

    • 查看内存信息
      free/vmstat/top/htop

    • 查看磁盘信息
      iostat

    • 查看CPU信息
      vmstat/top/htop

    • 查看网络信息
      netstat -i 网卡信息
      netstat -a 连接信息
      lsof -i:PORT 查看端口占用信息

    • proc目录的实现原理
      procfs,内部使用sysctl实现
      gdb调试,线程信息,线程栈

    • info stack/bt 调用栈
      info threads 线程信息
      thread id 切换线程
      watch expr 监控指定表达式
      buffer、cache和total的含义

    • IO写入时存放数据的内存page buffer
      IO读取时存放数据的内存page cache

    • 进程和线程的区别
      对于Linux内核而言,区别并不是很大。
      进程的隔离级别更加高,可以使用命名空间等,IPC的代价稍大。
      线程间共享进程的地址空间,所以数据交互更容易,代价也稍小,但是数据竞争更加严重,且一旦进程crash,所有线程也就不存在了。

    • 进程切换所做的事情
      保存寄存器现场
      切换栈空间
      处理内存页(最好深入一下)
      线程同步机制

    • 互斥锁、自旋锁、读写锁、条件变量

    • 列举进程通讯的方式
      PIPE、共享内存、Socket、文件、MQ等
      其中共享内存最快,但是需要额外的工作才能保证数据的一致性

    • 命名空间及其效果
      UTS、IPC、PID、NS、NET、USER

    • cgroup的功能
      限制CPU和内存的使用量/使用频率

    • VFS文件系统
      磁盘中数据的存放

    • IO调度算法
      为何需要IO调度?结合机械硬盘的工作原理,随机读写开销很大,因此可以通过汇总数据的方式实现顺序读写。
      Anticipatory算法、Deadline算法、CFQ算法以及Noop(No Operation)算法
      NOOP算法是最简单的IO调度算法,适合SSD,只需要将IO请求入队列即可。
      虚拟地址、物理地址及其实现

    进程中可见的地址是虚拟地址,物理地址对应真实的内存,虚拟地址通过MMU映射成物理地址,Linux采用的是4级页表(PGD、PUD、PMD、PTE),最终对应到CR3寄存器。
    转换的方式为基址+“偏移”,由于页表保存在内存中,CPU访存代价过大,因此引入TLB缓存,每次映射时优先查找TLB。
    网络
    TCP状态图,结合握手和挥手

    注意同时打开和同时关闭即可,其余结合TCP状态转移图进行理解。
    异常状态的出现场景以及解决方案

    大量SYN_RECV状态的连接,大量TIME_WAIT状态的连接等。
    长连接和短连接

    短连接:数据请求到达后即关闭连接
    长链接:多次请求复用一次连接,需要清楚如何保证连接是否存活,如心跳信号等。
    TIME_WAIT的等待时间,MSL的意思

    MSL(Maximum Segment Lifetime)
    TIME_WAIT后并不能保证最终的ACK能够安全到达对端,因此需要预留重传的时间,即等待2MSL。
    可以通过SO_REUSEADDR规避2MSL的等待。
    RTT如何估计

    RTT(Round-Trip Time)
    开启SO_REUSEADDR后可能会出现什么问题

    可能接收到对端传回的FIN、RST等,造成莫名其妙的问题。
    TCP如何保证其可靠性

    重传机制、流量控制、拥塞控制
    IP序号重合对上层的影响

    由IP层负责在组包时解决,对上层无影响。
    内核如何解决accept的惊群问题

    使用了WQ_FLAG_EXCLUSIVE标记,确保只有一个进程会被唤醒。
    用户态如何解决accept的惊群问题

    多进程抢占自旋锁即可,使用pthread_spinlock或者共享内存+CAS自行实现。
    进一步讨论,如何在这个阶段提供负载均衡。
    数据库
    悲观锁和乐观锁

    SQL中如何使用锁

    索引的实现方式和作用

    加快数据检索的速度,但是写入时有相应的代价,所以适合读多写少的场景。
    内存通常使用B+树实现。
    编译相关
    解释器和编译器

    常见的误区:所谓变异,并非一定要求生成本地代码,只要从语言A转换到语言B,这个过程就是编译。
    编译的流程

    预处理-词法解析-文法解析-语义制导-抽象语法树(IR的一种)-三地址码(SSA)-优化(控制流图、数据流图)-汇编
    动态链接库和静态链接库的区别

    虚拟机如何重新加载脚本

    关于热更新的讨论

    分布式存储
    redis、rockdb、leveldb的存储布局

    SSD和HDD的区别使用场景

    机械结构:主控+多FLASH芯片 vs 电机+磁盘+磁车
    延迟:SSD的延迟至少比HDD低1个数量级
    寿命:SSD的寿命主要由P/E次数决定,因此适合多读少写的环境
    其实,对于顺序读写,hdd的开销也不是那么大,原因自己去计算,另外此处可以结合IO调度算法一起考察。
    锁和MVCC的适用场景

    视场景而定,如果数据竞争少,则优先使用MVCC,否则老老实实用锁。
    HDFS的读写操作

    metadata、membership的管理

    etcd或者zookeeper,真的很方便哦~
    副本一致性(RSM)

    通过最终一致性算法,如Paxos、2PC、3PC、Raft等
    主从使用push和pull的优缺点

    1.进程和线程的区别
    2.什么叫线程安全?举例说明
    3.OSI七层模型,包括TCP,IP的一些基本知识
    4.数据库的锁
    5.DFS,BFS算法
    6.还有一些诸如collection framework的Java基础
    7、http中,get post的区别


    基础知识:
    算法和数据结构
    数组、链表、二叉树、队列、栈的各种操作(性能,场景)
    二分查找和各种变种的二分查找
    各类排序算法以及复杂度分析(快排、归并、堆)
    各类算法题(手写)
    理解并可以分析时间和空间复杂度。
    动态规划(笔试回回有。。)、贪心。
    红黑树、AVL树、Hash树、Tire树、B树、B 树。
    图算法(比较少,也就两个最短路径算法理解吧)
    计算机网络
    OSI7层模型(TCP4层)
    每层的协议
    url到页面的过程
    HTTP
    http/https 1.0、1.1、2.0
    get/post 以及幂等性
    http 协议头相关
    网络攻击(CSRF、XSS)
    TCP/IP
    三次握手、四次挥手
    拥塞控制(过程、阈值)
    流量控制与滑动窗口
    TCP与UDP比较
    子网划分(一般只有笔试有)
    DDos攻击
    (B)IO/NIO/AIO
    三者原理,各个语言是怎么实现的
    Netty
    Linux内核select poll epoll
    数据库(最多的还是mysql,Nosql有redis)
    索引(包括分类及优化方式,失效条件,底层结构)
    sql语法(join,union,子查询,having,group by)
    引擎对比(InnoDB,MyISAM)
    数据库的锁(行锁,表锁,页级锁,意向锁,读锁,写锁,悲观锁,乐观锁,以及加锁的select sql方式)
    隔离级别,依次解决的问题(脏读、不可重复读、幻读)
    事务的ACID
    B树、B 树
    优化(explain,慢查询,show profile)
    数据库的范式。
    分库分表,主从复制,读写分离。
    Nosql相关(redis和memcached区别之类的,如果你熟悉redis,redis还有一堆要问的)
    操作系统:
    进程通信IPC(几种方式),与线程区别
    OS的几种策略(页面置换,进程调度等,每个里面有几种算法)
    互斥与死锁相关的
    linux常用命令(问的时候都会给具体某一个场景)
    Linux内核相关(select、poll、epoll)
    编程语言(这里只说Java):
    把我之后的面经过一遍,Java感觉覆盖的就差不多了,不过下面还是分个类。
    Java基础(面向对象、四个特性、重载重写、static和final等等很多东西)
    集合(HashMap、ConcurrentHashMap、各种List,最好结合源码看)
    并发和多线程(线程池、SYNC和Lock锁机制、线程通信、volatile、ThreadLocal、CyclicBarrier、Atom包、CountDownLatch、AQS、CAS原理等等)
    JVM(内存模型、GC垃圾回收,包括分代,GC算法,收集器、类加载和双亲委派、JVM调优,内存泄漏和内存溢出)
    IO/NIO相关
    反射和代理、异常、Java8相关、序列化
    设计模式(常用的,jdk中有的)
    Web相关(servlet、cookie/session、Spring<AOP、IOC、MVC、事务、动态代理>、Mybatis、Tomcat、Hibernate等)

    一个url到页面全过程(让我能说多详细说多详细,最好从OSI七层的每一层去扩展)
    http的请求头格式(这个真的记不太清了,只说了几个有印象的标志位)
    getpost区别,post可不可以用url的方式传参。
    说到了url有最大长度,就问长度有限制是get的原因还是url的原因,为什么长度会有限制,是http数据包的头的字段原因还是内容字段的原因,详细说明。(在他一步步追问下答了个差不多)
    关于幂等性的详细介绍。
    幂等性是http层面的问题吗,还是服务器要处理和解决的内容。(就是看你对幂等性的定性是怎么理解的)
    后台服务器对于一个请求是如何做负载均衡的,有哪些策略,会出现什么样的问题,怎么解决。(说了一致性hash算法,分布式hash的特性,具体的应用场景,又非要问我知不知道这个最早在哪个公司使用的...我说这个真不知道。好像是amazon?)
    说说http的缺点,无状态,明文传输。
    那https是怎么做的,如何实现的?ca认证机构。
    然后问我https ssl tcp三者关系,其中哪些用到了对称加密,哪些用到了非对称加密,非对称加密密钥是如何实现的。(还好我项目中涉及到了一些加密)
    关于加密的私钥和公钥各自如何分配(客户端拿公钥,服务器拿私钥)
    那客户端是如何认证服务器的真实身份,详细说明一下过程,包括公钥如何申请,哪一层加密哪一层解密。
    java的优先级队列,如果让你设计一个数据结构实现优先级队列如何做?
    用TreeMap复杂度太高,有没有更好的方法。
    hash方法,但是队列不是定长的,如果改变了大小要rehash代价太大,还有什么方法?
    用堆实现,那每次get put复杂度是多少(lgN)
    (思想就是并不一定要按优先级排队列的所有对象,复杂度太高,但每次保证能取最大的就行,剩下的顺序不用保证,用堆调整最为合适)
    在线编程题:敲一个字串匹配问题,写了常规代码。问kmp的代码思想,最后问了下正则中用的改进后的BM算法。(还有个比较新奇的Sunday算法,有兴趣的同学也可以看一下)

    相关文章

      网友评论

          本文标题:面试基础知识

          本文链接:https://www.haomeiwen.com/subject/xsvivftx.html