Q1:什么是 AVL 树?
AVL 树 是平衡⼆叉查找树,增加和删除节点后通过树形旋转重新达到平衡。右旋是以某个节点为中⼼,
将它沉⼊当前右⼦节点的位置,⽽让当前的左⼦节点作为新树的根节点,也称为顺时针旋转。同理左旋
是以某个节点为中⼼,将它沉⼊当前左⼦节点的位置,⽽让当前的右⼦节点作为新树的根节点,也称为
逆时针旋转。
Q2:什么是红⿊树?
红⿊树 是 1972 年发明的,称为对称⼆叉 B 树,1978 年正式命名红⿊树。主要特征是在每个节点上增
加⼀个属性表示节点颜⾊,可以红⾊或⿊⾊。红⿊树和 AVL 树 类似,都是在进⾏插⼊和删除时通过旋
转保持⾃身平衡,从⽽获得较⾼的查找性能。与 AVL 树 相⽐,红⿊树不追求所有递归⼦树的⾼度差不
超过 1,保证从根节点到叶尾的最⻓路径不超过最短路径的 2 倍,所以最差时间复杂度是 O(logn)。红
⿊树通过重新着⾊和左右旋转,更加⾼效地完成了插⼊和删除之后的⾃平衡调整。
红⿊树在本质上还是⼆叉查找树,它额外引⼊了 5 个约束条件: ① 节点只能是红⾊或⿊⾊。 ② 根节点
必须是⿊⾊。 ③ 所有 NIL 节点都是⿊⾊的。 ④ ⼀条路径上不能出现相邻的两个红⾊节点。 ⑤ 在任何
递归⼦树中,根节点到叶⼦节点的所有路径上包含相同数⽬的⿊⾊节点。
这五个约束条件保证了红⿊树的新增、删除、查找的最坏时间复杂度均为 O(logn)。如果⼀个树的左⼦
节点或右⼦节点不存在,则均认定为⿊⾊。红⿊树的任何旋转在 3 次之内均可完成。
Q3:AVL 树和红⿊树的区别?
红⿊树的平衡性不如 AVL 树,它维持的只是⼀种⼤致的平衡,不严格保证左右⼦树的⾼度差不超过 1。
这导致节点数相同的情况下,红⿊树的⾼度可能更⾼,也就是说平均查找次数会⾼于相同情况的 AVL
树。
在插⼊时,红⿊树和 AVL 树都能在⾄多两次旋转内恢复平衡,在删除时由于红⿊树只追求⼤致平衡,因
此红⿊树⾄多三次旋转可以恢复平衡,⽽ AVL 树最多需要 O(logn) 次。AVL 树在插⼊和删除时,将向上
回溯确定是否需要旋转,这个回溯的时间成本最差为 O(logn),⽽红⿊树每次向上回溯的步⻓为 2,回
溯成本低。因此⾯对频繁地插⼊与删除红⿊树更加合适
Q4:B树和B+树的区别?
B 树中每个节点同时存储 key 和 data,⽽ B+ 树中只有叶⼦节点才存储 data,⾮叶⼦节点只存储 key。
InnoDB 对 B+ 树进⾏了优化,在每个叶⼦节点上增加了⼀个指向相邻叶⼦节点的链表指针,形成了带
有顺序指针的 B+ 树,提⾼区间访问的性能。
B+ 树的优点在于: ① 由于 B+ 树在⾮叶⼦节点上不含数据信息,因此在内存⻚中能够存放更多的
key,数据存放得更加紧密,具有更好的空间利⽤率,访问叶⼦节点上关联的数据也具有更好的缓存命
中率。 ② B+树的叶⼦结点都是相连的,因此对整棵树的遍历只需要⼀次线性遍历叶⼦节点即可。⽽ B
树则需要进⾏每⼀层的递归遍历,相邻的元素可能在内存中不相邻,所以缓存命中性没有 B+树好。但
是 B 树也有优点,由于每个节点都包含 key 和 value,因此经常访问的元素可能离根节点更近,访问也
更迅速。
Q5:排序有哪些分类?
排序可以分为内部排序和外部排序,在内存中进⾏的称为内部排序,当数据量很⼤时⽆法全部拷⻉到内
存需要使⽤外存,称为外部排序。
内部排序包括⽐较排序和⾮⽐较排序,⽐较排序包括插⼊/选择/交换/归并排序,⾮⽐较排序包括计数/
基数/桶排序。
插⼊排序包括直接插⼊/希尔排序,选择排序包括直接选择/堆排序,交换排序包括冒泡/快速排序。
Q6:直接插⼊排序的原理?
稳定,平均/最差时间复杂度 O(n²),元素基本有序时最好时间复杂度 O(n),空间复杂度 O(1)。
每⼀趟将⼀个待排序记录按其关键字的⼤⼩插⼊到已排好序的⼀组记录的适当位置上,直到所有待排序
记录全部插⼊为⽌。
public void insertionSort(int[] nums) {
for (int i = 1; i < nums.length; i++) {
int insertNum = nums[i];
int insertIndex;
for (insertIndex = i - 1; insertIndex >= 0 && nums[insertIndex] >
insertNum; insertIndex--) {
nums[insertIndex + 1] = nums[insertIndex];
}
nums[insertIndex + 1] = insertNum;
}
}
直接插⼊没有利⽤到要插⼊的序列已有序的特点,插⼊第 i 个元素时可以通过⼆分查找找到插⼊位置
insertIndex,再把 i~insertIndex 之间的所有元素后移⼀位,把第 i 个元素放在插⼊位置上。
public void binaryInsertionSort(int[] nums) {
for (int i = 1; i < nums.length; i++) {
int insertNum = nums[i];
int insertIndex = -1;
int start = 0;
int end = i - 1;
while (start <= end) {
int mid = start + (end - start) / 2;
if (insertNum > nums[mid])
start = mid + 1;
else if (insertNum < nums[mid])
end = mid - 1;
else {
insertIndex = mid + 1;