文章目录
- 数据结构面试题及答案
- 数组问题
- 字符串相关问题
- 链表问题
- 二叉树问题
- 编程面试问题之杂项
- 答案
数据结构与算法
时间复杂度
并不是计算程序具体运行的时间,而是算法执行语句的次数
O(2^n) 表示对 n 数据处理需要进行 2^n 次计算
多项式的时间复杂度 数据 n 在表达式的下方 O(1) O(log(n)) O(n^a)
非多项式时间复杂度 O(a^n) 和 O(n!)
空间复杂度
一个算法在运行过程中临时占用存储空间大小的量度
O(n)表示需要临时存储 n 个数据
NP 问题
P:能在多项式时间复杂度内解决的问题
NP:能在多项式时间复杂度内验证答案正确与否的问题
NP-hard:比 NP 问题更难的问题(NP 问题的解法可以规约到 NP-hard 问题的解法)
NP 完全问题:是一个 NP-hard 问题,也是一个 NP 问题
数组
数组的特性
创建数组必须要内存中一块连续的空间
数组中必须存放相同的数据类型
因为数组的这两个特性,所以数组支持随机快速读写。数组可以根据第一个数据的内存地址和数据类型,推导出任意下标的内存地址。根据下标访问数据,时间复杂度为 O(1)。
在数组中删除数据(不是数组末尾的数据)到导致数据迁移,时间复杂度为 O(n)。
链表
链表的特性
链表可以用零散的内存空间存储数据
链表中的每个数据元素都必须包含一个指向下一个数据元素的内存地址指针
要想在链表中查找一个数据,只能遍历链表,所以链表的查找复杂度总是 O(N)。
总体来说,在链表中增删数据要比数组性能好很多。
Hash 表
hash 表本质是一个数组。
数据存入 hash 表的过程:数据以 key value 的方式存储在 hash 表中。先计算 key 的 hash 值,然后用 hash 值和 hash 表的长度取模,余数就是 hash 表的下标。如果这个下标地址已经存入了数据,那么新数据会放在老数据后面,形成一个链表。
哈希碰撞攻击就是,针对哈希函数的特性,精心构造数据,使所有数据的哈希值相同,当这些数据保存到哈希表中,哈希表就会退化为单链表,哈希表的各种操作的时间复杂度提升一个数量级,因此会消耗大量 CPU 资源,导致系统无法快速响应请求,从而达到拒绝服务攻击(Dos)的目的。
栈
栈的特性
操作受限的线性表
“先进后出”
典型应用场景,线程调用栈
队列
操作受限的线性表
“先进先出”
典型应用场景,生产消费者队列
例子 用队列搜索好友关系最近的有钱人,用队列搜索最短路径
树
二叉排序树
左子树上所有结点的值均小于或等于它的根结点的值。右子树上所有结点的值均大于或等于它根结点的值。
不平衡的二叉排序树
平衡二叉排序树
旋转二叉树恢复平衡
红黑树(排序树)
红黑树 vs 平衡二叉树
红黑树最多只需 3 次旋转就会重新达成红黑平衡,时间复杂度 O(1)
在大量增删的情况下,红黑树的效率更高。
红黑树的平衡性不如二叉树,查找效率要差一些。
跳表
常用算法
穷举算法
递归算法
贪心算法
动态规划
递归算法用于实现快速排序,时间复杂度为 n*logn
迪杰斯特拉算法(最快路径)是改进的贪心算法。
动态规划解决背包问题。
遗传算法解决背包问题。
网络通信协议
OSI 七层模型和 TCP/IP 四层模型
物理层
在真正的通信线路里有光纤,电缆,无线各种设备。光信号和电信号以及无线电磁信号在物理上是完全不同的,如何让这些不同的设备能够理解,处理相同的二进制数据,这是物理层要解决的问题。
电信号用高电压和低电压表示 0 和 1 。
链路层
链路层就是将数据进行封装后交给物理层进行传输,主要就是将数据封装成数据帧,以帧为单位通过物理层进行通信,有了帧,就可以在帧上进行数据校验,进行流量控制。
链路层会定义帧的大小,这个大小也被称为最大传输单元。MAC 地址是网卡的设备标识符,是唯一的,数据帧通过这个信息确保数据送达到正确的目标机器。
链路层可以使用数据链路层负载均衡。
网络层(IP 协议)
网络层的数据需要交给链路层进行处理,而链路层帧的大小定义了最大传输单元,网络层的 IP 数据包必须要小于最大传输单元才能进行网络传输。
网络的数据包会定义一个 IP 头,这个 IP 头里包含了网络层的元信息,包括发送者和接受者的 IP 地址。
网络层可以使用 IP 负载均衡。
传输层(TCP 协议)
IP 协议不是一个可靠的通信协议,不会建立稳定的通信链路,并不会确保数据一定送达。要保证通信的稳定可靠,需要传输层协议 TCP。
TCP 协议是一种面向连接的,可靠的,基于字节流的传输层协议。
有很多重要的机制保证了 TCP 协议的可靠性和强壮性:
使用序号,对收到的 TCP 报文进行排序和检测重复的数据
无错传输,使用校验和检测报文段的错误
使用确认和计数器来检测和纠正丢包或者延时
流量控制,避免主机分组发送的过快而使接收方来不及完全收下
拥塞控制,发送方根据网络承载情况控制分组的发送量,以获得高性能同时避免拥塞崩溃丢失包的重传
TCP 建立连接的三次握手,关闭连接的四次挥手。
应用层 Http 协议
Http 请求的 7 种方法:get,post,put,delete,head,trace,options
Http 响应的 5 种状态
1XX: 消息 请求已被接收,继续处理
2XX: 成功
3XX:重定向
4XX:请求错误 请求含有词法错误或者无法被执行
5XX:服务器错误
Http 协议回复的格式
Http 协议的版本,1.0,1.1, 2 ,3。各个版本的区别,解决了什么问题。
非阻塞 I/O
BIO:进行 I/O 操作时,用户线程会一直阻塞,直到读操作或写操作完成
非阻塞 I/O: I/O 操作立即返回,发起线程不会阻塞等待
非阻塞 read 操作:
Socket 接收缓冲区有数据,读 n 个(不保证数据被读完整,因此有可能需要多次读)。
Socket 接收缓冲区没数据,则返回失败(不会等待)。
非阻塞 write:
Socket 发送缓冲区满,返回失败(不会等待)。
Socket 发送缓冲区不满,写 n 个数据(不保证一次性全部写入,因此可能需要多次写)。
Java NIO(New IO)的核心类:Selector,SelectableChannel,Buffer,SelectionKey
系统 I/O 复用的方式:select,poll,epoll
数据库架构原理与性能分析
数据块架构:连接器,语法分析器,语义分析与优化器,执行引擎。
这四个部分是解耦的,每个部分可以重新开发,用其他独立开发的一样功能的模块替换。比如开源社区就为 mysql 开发了很多执行引擎,innodb 引擎就是其他公司开发的,后来被 mysql 放进了发行包中,作为默认引擎。
连接器
数据库连接器会为每个连接请求分配一块专用的内存空间用于会话上下文管理。建立连
接对数据库而言相对比较重,需要花费一定的时间/因此应用程序启动的时候,通常会 初始化建立一些数据库连接放在连接池里,这样当处理外部请求执行 SQL 操作的时候’ 就不需要花费时间建立连接了。
语义分析与优化器
语义分析与优化器就是要将各种复杂嵌套的 SQL 进行语义等价转化,得到有限几种关系 代数计算结构,并利用索引等信息进一步进行优化。
为什么 PrepareStatement 更好
PrepareStatement 会预先提交带占位符的 SQL 到数据库进行预处理,提前生成执行计 划/当给定占位符参数,真正执行 SQL 的时候,执行引擎可以直接执行,效率更好一点。
PrepareStatement 可以防止 SQL 注入攻击
聚簇索引
聚簇索引:聚簇索引的数据库记录和索引存储在一起。
MySQL 数据库的主键就是聚簇索引/主键 ID 和所在的记录行存储在一个 B+树中
非聚簇索引
非聚簇索引在叶子节点记录的就不是数据行记录,而是聚簇索引,也就是主键。 通过非聚簇索引找到主键索引/再通过主键索引找到行记录的过程也被称作回表。
添加必要的索引优化 SQL 查询性能
在几百万行的数据库中查找一个条记录/如果没有索引,就需要全表扫描,检索所有的 行记录,才能找到需要的记录。
谨慎使用索引
不要盲目添加索引,尤其在生产环境中
•添加索引的 alter 操作会消耗较长的时间(分钟级)
• Alter 操作期间,所有数据库的增删改操作全部阻塞,对应用而言,因为连接不能释放,事实 上,查询也被阻塞。
删除不用的索引,避免不必要的增删开销
使用更小的数据类型创建索引
数据库事务
事务特性 ACID
•原子性(Atomicity): 事务要么全部完成,要么全部取消。如果事务崩溃,状态回到事 务之前(事务回滚)。
•隔离性(Isolation): 如果 2 个事务 T1 和 T2 同时运行,事务 T1 和 T2 最终的结果是相同 的,不管 T1 和 T2 谁先结束,隔离性主要依靠锁实现。
•持久性(Durability): 一旦事务提交,不管发生什么(崩溃或者出错),数据要保存在数 据库中。
• 一致性(Consistency): 只有合法的数据(依照关系约束和函数约束)才能写入数据库。
数据库事务日志
进行事务操作时,事务日志文件会记录更新前的数据记录’然后再更新数据库中的记录’ 如果全部记录都更新成功,那么事务正常结束,如果过程中某条记录更新失败,那么整 个事务全部回滚,已经更新的记录根据事务日志中记录的数据进行恢复,这样全部数据 都恢复到事务提交前的状态,仍然保持数据一致性。
LSN :一个按时间顺序分配的唯一事务记录日志序列号。
TransID:产生操作的事务 ID。
PagelD:被修改的数据在磁盘上的位置。
PrevLSN :同一个事务产生的上一条日志记录的指针。
UNDO:取消本次操作的方法,按照此方法回滚。
REDO:重复本次操作的方法。
数据结构面试题及答案
数组问题
**1、**在一个给定的从1到100的整型数组中,如何快速找到缺失的数字?
**2、**如何找到一个给定的整型数组中的重复数字?
**3、**在一个未排序的整型数组中,如何找到最大和最小的数字?
4、在一个整型数组中,如何找到一个所有成对的数字,满足它们的和等于一个给定的数字?
**5、**如果一个数组包含多个重复元素,如何找到这些重复的数字?
**6、**用 Java 实现从一个给定数组中删除重复元素?
**7、**如何利用快速排序对一个整型数组进行排序?
**8、**如何从一个数组中删除重复元素?
**9、**用 Java 实现数组反转?
**10、**如何不借助库实现从数组中删除重复元素?
字符串相关问题
**1、**如何输出字符串中的重复字符?
**2、**如何判断两个字符串是否互为回文?
**3、**如何从字符串中输出第一个不重复字符?
**4、**如何使用递归实现字符串反转?
**5、**如何检查字符仅包含数字字符?
**6、**如何在字符串中找到重复字符?
**7、**如何对给定字符串中的元音及辅音进行计数?
**8、**如何计算给定字符传中特定字符出现的次数?
**9、**如何找到一个字符串的全排列?
**10、**在不使用任何库方法的情况下如何反转给定语句中的单词?
**11、**如何判断两个字符串是否互为旋转?
**12、**如何判断给定字符串是否是回文?
链表问题
**1、**在一次遍历中,怎样发现单个链表的中间元素?
**2、**怎样验证给定的链表是环形的? 怎样发现这个环的起始节点?
**3、**怎样翻转链表?
**4、**不使用递归,怎样反转单个链表?
**5、**在未排序链表中,怎样移除重复的节点?
**6、**怎样找出单个链表的长度?
**7、**从单个链表的结尾处,怎样找出链表的第三个节点?
**8、**怎样使用栈计算两个链表的和?
二叉树问题
**1、**二叉搜索树是如何实现的?
**2、**如何在给定二叉树上实现前序遍历?
**3、**不使用递归如何按照前序遍历给定二叉树?
**4、**如何在给定二叉树上实现中序遍历?
**5、**不使用递归情况下如何使用中序遍历输出给定二叉树所有节点?
**6、**如何实现后序遍历算法?
**7、**如何不使用递归实现二叉树的后续遍历?
**8、**如何输出二叉搜索树的所有叶节点?
**9、**如何在给定二叉树中计算叶节点数目?
**10、**如何在给定数组中执行二分搜索?
编程面试问题之杂项
**1、**冒泡排序是如何实现的?
**2、**迭代式快排算法是如何实现的?
**3、**你如何实现插入排序算法?
**4、**合并排序算法是如何实现的?
**5、**桶排序算法是如何实现的?
**6、**计数排序算法是如何实现的?
**7、**基数排序算法是如何实现的?
**8、**在不使用第三个变量的前提下如何交换两个数?
**9、**如何检查两个矩形是否重叠?
**10、**如何设计一个自动售货机?